Fix 'rename' on MS-Windows
[emacs.git] / src / w32.c
blobc821e245d8340bb500760be43c31c1f11bd745f5
1 /* Utility and Unix shadow routines for GNU Emacs on the Microsoft Windows API.
3 Copyright (C) 1994-1995, 2000-2017 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or (at
10 your option) any later version.
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
21 Geoff Voelker (voelker@cs.washington.edu) 7-29-94
24 #define DEFER_MS_W32_H
25 #include <config.h>
27 #include <mingw_time.h>
28 #include <stddef.h> /* for offsetof */
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <float.h> /* for DBL_EPSILON */
32 #include <io.h>
33 #include <errno.h>
34 #include <fcntl.h>
35 #include <ctype.h>
36 #include <signal.h>
37 #include <sys/file.h>
38 #include <time.h> /* must be before nt/inc/sys/time.h, for MinGW64 */
39 #include <sys/time.h>
40 #include <sys/utime.h>
41 #include <math.h>
43 /* Include (most) CRT headers *before* ms-w32.h. */
44 #include <ms-w32.h>
46 #include <string.h> /* for strerror, needed by sys_strerror */
47 #include <mbstring.h> /* for _mbspbrk, _mbslwr, _mbsrchr, ... */
49 #undef access
50 #undef chdir
51 #undef chmod
52 #undef creat
53 #undef ctime
54 #undef fopen
55 #undef link
56 #undef mkdir
57 #undef open
58 #undef rename
59 #undef rmdir
60 #undef unlink
62 #undef close
63 #undef dup
64 #undef dup2
65 #undef pipe
66 #undef read
67 #undef write
69 #undef strerror
71 #undef localtime
73 char *sys_ctime (const time_t *);
74 int sys_chdir (const char *);
75 int sys_creat (const char *, int);
76 FILE *sys_fopen (const char *, const char *);
77 int sys_open (const char *, int, int);
78 int sys_rename (char const *, char const *);
79 int sys_rmdir (const char *);
80 int sys_close (int);
81 int sys_dup2 (int, int);
82 int sys_read (int, char *, unsigned int);
83 int sys_write (int, const void *, unsigned int);
84 struct tm *sys_localtime (const time_t *);
86 #ifdef HAVE_MODULES
87 extern void dynlib_reset_last_error (void);
88 #endif
90 #include "lisp.h"
91 #include "epaths.h" /* for PATH_EXEC */
93 #include <pwd.h>
94 #include <grp.h>
96 #include <windows.h>
97 /* Some versions of compiler define MEMORYSTATUSEX, some don't, so we
98 use a different name to avoid compilation problems. */
99 typedef struct _MEMORY_STATUS_EX {
100 DWORD dwLength;
101 DWORD dwMemoryLoad;
102 DWORDLONG ullTotalPhys;
103 DWORDLONG ullAvailPhys;
104 DWORDLONG ullTotalPageFile;
105 DWORDLONG ullAvailPageFile;
106 DWORDLONG ullTotalVirtual;
107 DWORDLONG ullAvailVirtual;
108 DWORDLONG ullAvailExtendedVirtual;
109 } MEMORY_STATUS_EX,*LPMEMORY_STATUS_EX;
111 /* These are here so that GDB would know about these data types. This
112 allows attaching GDB to Emacs when a fatal exception is triggered
113 and Windows pops up the "application needs to be closed" dialog.
114 At that point, _gnu_exception_handler, the top-level exception
115 handler installed by the MinGW startup code, is somewhere on the
116 call-stack of the main thread, so going to that call frame and
117 looking at the argument to _gnu_exception_handler, which is a
118 PEXCEPTION_POINTERS pointer, can reveal the exception code
119 (excptr->ExceptionRecord->ExceptionCode) and the address where the
120 exception happened (excptr->ExceptionRecord->ExceptionAddress), as
121 well as some additional information specific to the exception. */
122 PEXCEPTION_POINTERS excptr;
123 PEXCEPTION_RECORD excprec;
124 PCONTEXT ctxrec;
126 #include <lmcons.h>
127 #include <shlobj.h>
129 #include <tlhelp32.h>
130 #include <psapi.h>
131 #ifndef _MSC_VER
132 #include <w32api.h>
133 #endif
134 #if _WIN32_WINNT < 0x0500
135 #if !defined (__MINGW32__) || __W32API_MAJOR_VERSION < 3 || (__W32API_MAJOR_VERSION == 3 && __W32API_MINOR_VERSION < 15)
136 /* This either is not in psapi.h or guarded by higher value of
137 _WIN32_WINNT than what we use. w32api supplied with MinGW 3.15
138 defines it in psapi.h */
139 typedef struct _PROCESS_MEMORY_COUNTERS_EX {
140 DWORD cb;
141 DWORD PageFaultCount;
142 SIZE_T PeakWorkingSetSize;
143 SIZE_T WorkingSetSize;
144 SIZE_T QuotaPeakPagedPoolUsage;
145 SIZE_T QuotaPagedPoolUsage;
146 SIZE_T QuotaPeakNonPagedPoolUsage;
147 SIZE_T QuotaNonPagedPoolUsage;
148 SIZE_T PagefileUsage;
149 SIZE_T PeakPagefileUsage;
150 SIZE_T PrivateUsage;
151 } PROCESS_MEMORY_COUNTERS_EX,*PPROCESS_MEMORY_COUNTERS_EX;
152 #endif
153 #endif
155 #include <winioctl.h>
156 #include <aclapi.h>
157 #include <sddl.h>
159 #include <sys/acl.h>
160 #include <acl.h>
162 /* This is not in MinGW's sddl.h (but they are in MSVC headers), so we
163 define them by hand if not already defined. */
164 #ifndef SDDL_REVISION_1
165 #define SDDL_REVISION_1 1
166 #endif /* SDDL_REVISION_1 */
168 #if defined(_MSC_VER) || defined(MINGW_W64)
169 /* MSVC and MinGW64 don't provide the definition of
170 REPARSE_DATA_BUFFER and the associated macros, except on ntifs.h,
171 which cannot be included because it triggers conflicts with other
172 Windows API headers. So we define it here by hand. */
174 typedef struct _REPARSE_DATA_BUFFER {
175 ULONG ReparseTag;
176 USHORT ReparseDataLength;
177 USHORT Reserved;
178 union {
179 struct {
180 USHORT SubstituteNameOffset;
181 USHORT SubstituteNameLength;
182 USHORT PrintNameOffset;
183 USHORT PrintNameLength;
184 ULONG Flags;
185 WCHAR PathBuffer[1];
186 } SymbolicLinkReparseBuffer;
187 struct {
188 USHORT SubstituteNameOffset;
189 USHORT SubstituteNameLength;
190 USHORT PrintNameOffset;
191 USHORT PrintNameLength;
192 WCHAR PathBuffer[1];
193 } MountPointReparseBuffer;
194 struct {
195 UCHAR DataBuffer[1];
196 } GenericReparseBuffer;
197 } DUMMYUNIONNAME;
198 } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
200 #ifndef FILE_DEVICE_FILE_SYSTEM
201 #define FILE_DEVICE_FILE_SYSTEM 9
202 #endif
203 #ifndef METHOD_BUFFERED
204 #define METHOD_BUFFERED 0
205 #endif
206 #ifndef FILE_ANY_ACCESS
207 #define FILE_ANY_ACCESS 0x00000000
208 #endif
209 #ifndef CTL_CODE
210 #define CTL_CODE(t,f,m,a) (((t)<<16)|((a)<<14)|((f)<<2)|(m))
211 #endif
212 /* MinGW64 defines FSCTL_GET_REPARSE_POINT on winioctl.h. */
213 #ifndef FSCTL_GET_REPARSE_POINT
214 #define FSCTL_GET_REPARSE_POINT \
215 CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS)
216 #endif
217 #endif
219 /* TCP connection support. */
220 #include <sys/socket.h>
221 #undef socket
222 #undef bind
223 #undef connect
224 #undef htons
225 #undef ntohs
226 #undef inet_addr
227 #undef gethostname
228 #undef gethostbyname
229 #undef getservbyname
230 #undef getpeername
231 #undef shutdown
232 #undef setsockopt
233 #undef listen
234 #undef getsockname
235 #undef accept
236 #undef recvfrom
237 #undef sendto
239 #include <iphlpapi.h> /* should be after winsock2.h */
241 #include <wincrypt.h>
243 #include <c-strcase.h>
244 #include <utimens.h> /* for fdutimens */
246 #include "w32.h"
247 #include <dirent.h>
248 #include "w32common.h"
249 #include "w32select.h"
250 #include "systime.h" /* for current_timespec, struct timespec */
251 #include "dispextern.h" /* for xstrcasecmp */
252 #include "coding.h" /* for Vlocale_coding_system */
254 #include "careadlinkat.h"
255 #include "allocator.h"
257 /* For Lisp_Process, serial_configure and serial_open. */
258 #include "process.h"
259 #include "systty.h"
261 typedef HRESULT (WINAPI * ShGetFolderPath_fn)
262 (IN HWND, IN int, IN HANDLE, IN DWORD, OUT char *);
264 static DWORD get_rid (PSID);
265 static int is_symlink (const char *);
266 static char * chase_symlinks (const char *);
267 static int enable_privilege (LPCTSTR, BOOL, TOKEN_PRIVILEGES *);
268 static int restore_privilege (TOKEN_PRIVILEGES *);
269 static BOOL WINAPI revert_to_self (void);
271 static int sys_access (const char *, int);
272 extern void *e_malloc (size_t);
273 extern int sys_select (int, SELECT_TYPE *, SELECT_TYPE *, SELECT_TYPE *,
274 const struct timespec *, const sigset_t *);
275 extern int sys_dup (int);
278 /* Initialization states.
280 WARNING: If you add any more such variables for additional APIs,
281 you MUST add initialization for them to globals_of_w32
282 below. This is because these variables might get set
283 to non-NULL values during dumping, but the dumped Emacs
284 cannot reuse those values, because it could be run on a
285 different version of the OS, where API addresses are
286 different. */
287 static BOOL g_b_init_is_windows_9x;
288 static BOOL g_b_init_open_process_token;
289 static BOOL g_b_init_get_token_information;
290 static BOOL g_b_init_lookup_account_sid;
291 static BOOL g_b_init_get_sid_sub_authority;
292 static BOOL g_b_init_get_sid_sub_authority_count;
293 static BOOL g_b_init_get_security_info;
294 static BOOL g_b_init_get_file_security_w;
295 static BOOL g_b_init_get_file_security_a;
296 static BOOL g_b_init_get_security_descriptor_owner;
297 static BOOL g_b_init_get_security_descriptor_group;
298 static BOOL g_b_init_is_valid_sid;
299 static BOOL g_b_init_create_toolhelp32_snapshot;
300 static BOOL g_b_init_process32_first;
301 static BOOL g_b_init_process32_next;
302 static BOOL g_b_init_open_thread_token;
303 static BOOL g_b_init_impersonate_self;
304 static BOOL g_b_init_revert_to_self;
305 static BOOL g_b_init_get_process_memory_info;
306 static BOOL g_b_init_get_process_working_set_size;
307 static BOOL g_b_init_global_memory_status;
308 static BOOL g_b_init_global_memory_status_ex;
309 static BOOL g_b_init_get_length_sid;
310 static BOOL g_b_init_equal_sid;
311 static BOOL g_b_init_copy_sid;
312 static BOOL g_b_init_get_native_system_info;
313 static BOOL g_b_init_get_system_times;
314 static BOOL g_b_init_create_symbolic_link_w;
315 static BOOL g_b_init_create_symbolic_link_a;
316 static BOOL g_b_init_get_security_descriptor_dacl;
317 static BOOL g_b_init_convert_sd_to_sddl;
318 static BOOL g_b_init_convert_sddl_to_sd;
319 static BOOL g_b_init_is_valid_security_descriptor;
320 static BOOL g_b_init_set_file_security_w;
321 static BOOL g_b_init_set_file_security_a;
322 static BOOL g_b_init_set_named_security_info_w;
323 static BOOL g_b_init_set_named_security_info_a;
324 static BOOL g_b_init_get_adapters_info;
326 BOOL g_b_init_compare_string_w;
327 BOOL g_b_init_debug_break_process;
330 BEGIN: Wrapper functions around OpenProcessToken
331 and other functions in advapi32.dll that are only
332 supported in Windows NT / 2k / XP
334 /* ** Function pointer typedefs ** */
335 typedef BOOL (WINAPI * OpenProcessToken_Proc) (
336 HANDLE ProcessHandle,
337 DWORD DesiredAccess,
338 PHANDLE TokenHandle);
339 typedef BOOL (WINAPI * GetTokenInformation_Proc) (
340 HANDLE TokenHandle,
341 TOKEN_INFORMATION_CLASS TokenInformationClass,
342 LPVOID TokenInformation,
343 DWORD TokenInformationLength,
344 PDWORD ReturnLength);
345 typedef BOOL (WINAPI * GetProcessTimes_Proc) (
346 HANDLE process_handle,
347 LPFILETIME creation_time,
348 LPFILETIME exit_time,
349 LPFILETIME kernel_time,
350 LPFILETIME user_time);
352 GetProcessTimes_Proc get_process_times_fn = NULL;
354 #ifdef _UNICODE
355 const char * const LookupAccountSid_Name = "LookupAccountSidW";
356 #else
357 const char * const LookupAccountSid_Name = "LookupAccountSidA";
358 #endif
359 typedef BOOL (WINAPI * LookupAccountSid_Proc) (
360 LPCTSTR lpSystemName,
361 PSID Sid,
362 LPTSTR Name,
363 LPDWORD cbName,
364 LPTSTR DomainName,
365 LPDWORD cbDomainName,
366 PSID_NAME_USE peUse);
367 typedef PDWORD (WINAPI * GetSidSubAuthority_Proc) (
368 PSID pSid,
369 DWORD n);
370 typedef PUCHAR (WINAPI * GetSidSubAuthorityCount_Proc) (
371 PSID pSid);
372 typedef DWORD (WINAPI * GetSecurityInfo_Proc) (
373 HANDLE handle,
374 SE_OBJECT_TYPE ObjectType,
375 SECURITY_INFORMATION SecurityInfo,
376 PSID *ppsidOwner,
377 PSID *ppsidGroup,
378 PACL *ppDacl,
379 PACL *ppSacl,
380 PSECURITY_DESCRIPTOR *ppSecurityDescriptor);
381 typedef BOOL (WINAPI * GetFileSecurityW_Proc) (
382 LPCWSTR lpFileName,
383 SECURITY_INFORMATION RequestedInformation,
384 PSECURITY_DESCRIPTOR pSecurityDescriptor,
385 DWORD nLength,
386 LPDWORD lpnLengthNeeded);
387 typedef BOOL (WINAPI * GetFileSecurityA_Proc) (
388 LPCSTR lpFileName,
389 SECURITY_INFORMATION RequestedInformation,
390 PSECURITY_DESCRIPTOR pSecurityDescriptor,
391 DWORD nLength,
392 LPDWORD lpnLengthNeeded);
393 typedef BOOL (WINAPI *SetFileSecurityW_Proc) (
394 LPCWSTR lpFileName,
395 SECURITY_INFORMATION SecurityInformation,
396 PSECURITY_DESCRIPTOR pSecurityDescriptor);
397 typedef BOOL (WINAPI *SetFileSecurityA_Proc) (
398 LPCSTR lpFileName,
399 SECURITY_INFORMATION SecurityInformation,
400 PSECURITY_DESCRIPTOR pSecurityDescriptor);
401 typedef DWORD (WINAPI *SetNamedSecurityInfoW_Proc) (
402 LPCWSTR lpObjectName,
403 SE_OBJECT_TYPE ObjectType,
404 SECURITY_INFORMATION SecurityInformation,
405 PSID psidOwner,
406 PSID psidGroup,
407 PACL pDacl,
408 PACL pSacl);
409 typedef DWORD (WINAPI *SetNamedSecurityInfoA_Proc) (
410 LPCSTR lpObjectName,
411 SE_OBJECT_TYPE ObjectType,
412 SECURITY_INFORMATION SecurityInformation,
413 PSID psidOwner,
414 PSID psidGroup,
415 PACL pDacl,
416 PACL pSacl);
417 typedef BOOL (WINAPI * GetSecurityDescriptorOwner_Proc) (
418 PSECURITY_DESCRIPTOR pSecurityDescriptor,
419 PSID *pOwner,
420 LPBOOL lpbOwnerDefaulted);
421 typedef BOOL (WINAPI * GetSecurityDescriptorGroup_Proc) (
422 PSECURITY_DESCRIPTOR pSecurityDescriptor,
423 PSID *pGroup,
424 LPBOOL lpbGroupDefaulted);
425 typedef BOOL (WINAPI *GetSecurityDescriptorDacl_Proc) (
426 PSECURITY_DESCRIPTOR pSecurityDescriptor,
427 LPBOOL lpbDaclPresent,
428 PACL *pDacl,
429 LPBOOL lpbDaclDefaulted);
430 typedef BOOL (WINAPI * IsValidSid_Proc) (
431 PSID sid);
432 typedef HANDLE (WINAPI * CreateToolhelp32Snapshot_Proc) (
433 DWORD dwFlags,
434 DWORD th32ProcessID);
435 typedef BOOL (WINAPI * Process32First_Proc) (
436 HANDLE hSnapshot,
437 LPPROCESSENTRY32 lppe);
438 typedef BOOL (WINAPI * Process32Next_Proc) (
439 HANDLE hSnapshot,
440 LPPROCESSENTRY32 lppe);
441 typedef BOOL (WINAPI * OpenThreadToken_Proc) (
442 HANDLE ThreadHandle,
443 DWORD DesiredAccess,
444 BOOL OpenAsSelf,
445 PHANDLE TokenHandle);
446 typedef BOOL (WINAPI * ImpersonateSelf_Proc) (
447 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel);
448 typedef BOOL (WINAPI * RevertToSelf_Proc) (void);
449 typedef BOOL (WINAPI * GetProcessMemoryInfo_Proc) (
450 HANDLE Process,
451 PPROCESS_MEMORY_COUNTERS ppsmemCounters,
452 DWORD cb);
453 typedef BOOL (WINAPI * GetProcessWorkingSetSize_Proc) (
454 HANDLE hProcess,
455 PSIZE_T lpMinimumWorkingSetSize,
456 PSIZE_T lpMaximumWorkingSetSize);
457 typedef BOOL (WINAPI * GlobalMemoryStatus_Proc) (
458 LPMEMORYSTATUS lpBuffer);
459 typedef BOOL (WINAPI * GlobalMemoryStatusEx_Proc) (
460 LPMEMORY_STATUS_EX lpBuffer);
461 typedef BOOL (WINAPI * CopySid_Proc) (
462 DWORD nDestinationSidLength,
463 PSID pDestinationSid,
464 PSID pSourceSid);
465 typedef BOOL (WINAPI * EqualSid_Proc) (
466 PSID pSid1,
467 PSID pSid2);
468 typedef DWORD (WINAPI * GetLengthSid_Proc) (
469 PSID pSid);
470 typedef void (WINAPI * GetNativeSystemInfo_Proc) (
471 LPSYSTEM_INFO lpSystemInfo);
472 typedef BOOL (WINAPI * GetSystemTimes_Proc) (
473 LPFILETIME lpIdleTime,
474 LPFILETIME lpKernelTime,
475 LPFILETIME lpUserTime);
476 typedef BOOLEAN (WINAPI *CreateSymbolicLinkW_Proc) (
477 LPCWSTR lpSymlinkFileName,
478 LPCWSTR lpTargetFileName,
479 DWORD dwFlags);
480 typedef BOOLEAN (WINAPI *CreateSymbolicLinkA_Proc) (
481 LPCSTR lpSymlinkFileName,
482 LPCSTR lpTargetFileName,
483 DWORD dwFlags);
484 typedef BOOL (WINAPI *ConvertStringSecurityDescriptorToSecurityDescriptor_Proc) (
485 LPCTSTR StringSecurityDescriptor,
486 DWORD StringSDRevision,
487 PSECURITY_DESCRIPTOR *SecurityDescriptor,
488 PULONG SecurityDescriptorSize);
489 typedef BOOL (WINAPI *ConvertSecurityDescriptorToStringSecurityDescriptor_Proc) (
490 PSECURITY_DESCRIPTOR SecurityDescriptor,
491 DWORD RequestedStringSDRevision,
492 SECURITY_INFORMATION SecurityInformation,
493 LPTSTR *StringSecurityDescriptor,
494 PULONG StringSecurityDescriptorLen);
495 typedef BOOL (WINAPI *IsValidSecurityDescriptor_Proc) (PSECURITY_DESCRIPTOR);
496 typedef DWORD (WINAPI *GetAdaptersInfo_Proc) (
497 PIP_ADAPTER_INFO pAdapterInfo,
498 PULONG pOutBufLen);
500 int (WINAPI *pMultiByteToWideChar)(UINT,DWORD,LPCSTR,int,LPWSTR,int);
501 int (WINAPI *pWideCharToMultiByte)(UINT,DWORD,LPCWSTR,int,LPSTR,int,LPCSTR,LPBOOL);
502 DWORD multiByteToWideCharFlags;
504 /* ** A utility function ** */
505 static BOOL
506 is_windows_9x (void)
508 static BOOL s_b_ret = 0;
509 OSVERSIONINFO os_ver;
510 if (g_b_init_is_windows_9x == 0)
512 g_b_init_is_windows_9x = 1;
513 ZeroMemory (&os_ver, sizeof (OSVERSIONINFO));
514 os_ver.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
515 if (GetVersionEx (&os_ver))
517 s_b_ret = (os_ver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
520 return s_b_ret;
523 static Lisp_Object ltime (ULONGLONG);
525 /* Get total user and system times for get-internal-run-time.
526 Returns a list of integers if the times are provided by the OS
527 (NT derivatives), otherwise it returns the result of current-time. */
528 Lisp_Object w32_get_internal_run_time (void);
530 Lisp_Object
531 w32_get_internal_run_time (void)
533 if (get_process_times_fn)
535 FILETIME create, exit, kernel, user;
536 HANDLE proc = GetCurrentProcess ();
537 if ((*get_process_times_fn) (proc, &create, &exit, &kernel, &user))
539 LARGE_INTEGER user_int, kernel_int, total;
540 user_int.LowPart = user.dwLowDateTime;
541 user_int.HighPart = user.dwHighDateTime;
542 kernel_int.LowPart = kernel.dwLowDateTime;
543 kernel_int.HighPart = kernel.dwHighDateTime;
544 total.QuadPart = user_int.QuadPart + kernel_int.QuadPart;
545 return ltime (total.QuadPart);
549 return Fcurrent_time ();
552 /* ** The wrapper functions ** */
554 static BOOL WINAPI
555 open_process_token (HANDLE ProcessHandle,
556 DWORD DesiredAccess,
557 PHANDLE TokenHandle)
559 static OpenProcessToken_Proc s_pfn_Open_Process_Token = NULL;
560 HMODULE hm_advapi32 = NULL;
561 if (is_windows_9x () == TRUE)
563 return FALSE;
565 if (g_b_init_open_process_token == 0)
567 g_b_init_open_process_token = 1;
568 hm_advapi32 = LoadLibrary ("Advapi32.dll");
569 s_pfn_Open_Process_Token =
570 (OpenProcessToken_Proc) GetProcAddress (hm_advapi32, "OpenProcessToken");
572 if (s_pfn_Open_Process_Token == NULL)
574 return FALSE;
576 return (
577 s_pfn_Open_Process_Token (
578 ProcessHandle,
579 DesiredAccess,
580 TokenHandle)
584 static BOOL WINAPI
585 get_token_information (HANDLE TokenHandle,
586 TOKEN_INFORMATION_CLASS TokenInformationClass,
587 LPVOID TokenInformation,
588 DWORD TokenInformationLength,
589 PDWORD ReturnLength)
591 static GetTokenInformation_Proc s_pfn_Get_Token_Information = NULL;
592 HMODULE hm_advapi32 = NULL;
593 if (is_windows_9x () == TRUE)
595 return FALSE;
597 if (g_b_init_get_token_information == 0)
599 g_b_init_get_token_information = 1;
600 hm_advapi32 = LoadLibrary ("Advapi32.dll");
601 s_pfn_Get_Token_Information =
602 (GetTokenInformation_Proc) GetProcAddress (hm_advapi32, "GetTokenInformation");
604 if (s_pfn_Get_Token_Information == NULL)
606 return FALSE;
608 return (
609 s_pfn_Get_Token_Information (
610 TokenHandle,
611 TokenInformationClass,
612 TokenInformation,
613 TokenInformationLength,
614 ReturnLength)
618 static BOOL WINAPI
619 lookup_account_sid (LPCTSTR lpSystemName,
620 PSID Sid,
621 LPTSTR Name,
622 LPDWORD cbName,
623 LPTSTR DomainName,
624 LPDWORD cbDomainName,
625 PSID_NAME_USE peUse)
627 static LookupAccountSid_Proc s_pfn_Lookup_Account_Sid = NULL;
628 HMODULE hm_advapi32 = NULL;
629 if (is_windows_9x () == TRUE)
631 return FALSE;
633 if (g_b_init_lookup_account_sid == 0)
635 g_b_init_lookup_account_sid = 1;
636 hm_advapi32 = LoadLibrary ("Advapi32.dll");
637 s_pfn_Lookup_Account_Sid =
638 (LookupAccountSid_Proc) GetProcAddress (hm_advapi32, LookupAccountSid_Name);
640 if (s_pfn_Lookup_Account_Sid == NULL)
642 return FALSE;
644 return (
645 s_pfn_Lookup_Account_Sid (
646 lpSystemName,
647 Sid,
648 Name,
649 cbName,
650 DomainName,
651 cbDomainName,
652 peUse)
656 static PDWORD WINAPI
657 get_sid_sub_authority (PSID pSid, DWORD n)
659 static GetSidSubAuthority_Proc s_pfn_Get_Sid_Sub_Authority = NULL;
660 static DWORD zero = 0U;
661 HMODULE hm_advapi32 = NULL;
662 if (is_windows_9x () == TRUE)
664 return &zero;
666 if (g_b_init_get_sid_sub_authority == 0)
668 g_b_init_get_sid_sub_authority = 1;
669 hm_advapi32 = LoadLibrary ("Advapi32.dll");
670 s_pfn_Get_Sid_Sub_Authority =
671 (GetSidSubAuthority_Proc) GetProcAddress (
672 hm_advapi32, "GetSidSubAuthority");
674 if (s_pfn_Get_Sid_Sub_Authority == NULL)
676 return &zero;
678 return (s_pfn_Get_Sid_Sub_Authority (pSid, n));
681 static PUCHAR WINAPI
682 get_sid_sub_authority_count (PSID pSid)
684 static GetSidSubAuthorityCount_Proc s_pfn_Get_Sid_Sub_Authority_Count = NULL;
685 static UCHAR zero = 0U;
686 HMODULE hm_advapi32 = NULL;
687 if (is_windows_9x () == TRUE)
689 return &zero;
691 if (g_b_init_get_sid_sub_authority_count == 0)
693 g_b_init_get_sid_sub_authority_count = 1;
694 hm_advapi32 = LoadLibrary ("Advapi32.dll");
695 s_pfn_Get_Sid_Sub_Authority_Count =
696 (GetSidSubAuthorityCount_Proc) GetProcAddress (
697 hm_advapi32, "GetSidSubAuthorityCount");
699 if (s_pfn_Get_Sid_Sub_Authority_Count == NULL)
701 return &zero;
703 return (s_pfn_Get_Sid_Sub_Authority_Count (pSid));
706 static DWORD WINAPI
707 get_security_info (HANDLE handle,
708 SE_OBJECT_TYPE ObjectType,
709 SECURITY_INFORMATION SecurityInfo,
710 PSID *ppsidOwner,
711 PSID *ppsidGroup,
712 PACL *ppDacl,
713 PACL *ppSacl,
714 PSECURITY_DESCRIPTOR *ppSecurityDescriptor)
716 static GetSecurityInfo_Proc s_pfn_Get_Security_Info = NULL;
717 HMODULE hm_advapi32 = NULL;
718 if (is_windows_9x () == TRUE)
720 return FALSE;
722 if (g_b_init_get_security_info == 0)
724 g_b_init_get_security_info = 1;
725 hm_advapi32 = LoadLibrary ("Advapi32.dll");
726 s_pfn_Get_Security_Info =
727 (GetSecurityInfo_Proc) GetProcAddress (
728 hm_advapi32, "GetSecurityInfo");
730 if (s_pfn_Get_Security_Info == NULL)
732 return FALSE;
734 return (s_pfn_Get_Security_Info (handle, ObjectType, SecurityInfo,
735 ppsidOwner, ppsidGroup, ppDacl, ppSacl,
736 ppSecurityDescriptor));
739 static BOOL WINAPI
740 get_file_security (const char *lpFileName,
741 SECURITY_INFORMATION RequestedInformation,
742 PSECURITY_DESCRIPTOR pSecurityDescriptor,
743 DWORD nLength,
744 LPDWORD lpnLengthNeeded)
746 static GetFileSecurityA_Proc s_pfn_Get_File_SecurityA = NULL;
747 static GetFileSecurityW_Proc s_pfn_Get_File_SecurityW = NULL;
748 HMODULE hm_advapi32 = NULL;
749 if (is_windows_9x () == TRUE)
751 errno = ENOTSUP;
752 return FALSE;
754 if (w32_unicode_filenames)
756 wchar_t filename_w[MAX_PATH];
758 if (g_b_init_get_file_security_w == 0)
760 g_b_init_get_file_security_w = 1;
761 hm_advapi32 = LoadLibrary ("Advapi32.dll");
762 s_pfn_Get_File_SecurityW =
763 (GetFileSecurityW_Proc) GetProcAddress (hm_advapi32,
764 "GetFileSecurityW");
766 if (s_pfn_Get_File_SecurityW == NULL)
768 errno = ENOTSUP;
769 return FALSE;
771 filename_to_utf16 (lpFileName, filename_w);
772 return (s_pfn_Get_File_SecurityW (filename_w, RequestedInformation,
773 pSecurityDescriptor, nLength,
774 lpnLengthNeeded));
776 else
778 char filename_a[MAX_PATH];
780 if (g_b_init_get_file_security_a == 0)
782 g_b_init_get_file_security_a = 1;
783 hm_advapi32 = LoadLibrary ("Advapi32.dll");
784 s_pfn_Get_File_SecurityA =
785 (GetFileSecurityA_Proc) GetProcAddress (hm_advapi32,
786 "GetFileSecurityA");
788 if (s_pfn_Get_File_SecurityA == NULL)
790 errno = ENOTSUP;
791 return FALSE;
793 filename_to_ansi (lpFileName, filename_a);
794 return (s_pfn_Get_File_SecurityA (filename_a, RequestedInformation,
795 pSecurityDescriptor, nLength,
796 lpnLengthNeeded));
800 static BOOL WINAPI
801 set_file_security (const char *lpFileName,
802 SECURITY_INFORMATION SecurityInformation,
803 PSECURITY_DESCRIPTOR pSecurityDescriptor)
805 static SetFileSecurityW_Proc s_pfn_Set_File_SecurityW = NULL;
806 static SetFileSecurityA_Proc s_pfn_Set_File_SecurityA = NULL;
807 HMODULE hm_advapi32 = NULL;
808 if (is_windows_9x () == TRUE)
810 errno = ENOTSUP;
811 return FALSE;
813 if (w32_unicode_filenames)
815 wchar_t filename_w[MAX_PATH];
817 if (g_b_init_set_file_security_w == 0)
819 g_b_init_set_file_security_w = 1;
820 hm_advapi32 = LoadLibrary ("Advapi32.dll");
821 s_pfn_Set_File_SecurityW =
822 (SetFileSecurityW_Proc) GetProcAddress (hm_advapi32,
823 "SetFileSecurityW");
825 if (s_pfn_Set_File_SecurityW == NULL)
827 errno = ENOTSUP;
828 return FALSE;
830 filename_to_utf16 (lpFileName, filename_w);
831 return (s_pfn_Set_File_SecurityW (filename_w, SecurityInformation,
832 pSecurityDescriptor));
834 else
836 char filename_a[MAX_PATH];
838 if (g_b_init_set_file_security_a == 0)
840 g_b_init_set_file_security_a = 1;
841 hm_advapi32 = LoadLibrary ("Advapi32.dll");
842 s_pfn_Set_File_SecurityA =
843 (SetFileSecurityA_Proc) GetProcAddress (hm_advapi32,
844 "SetFileSecurityA");
846 if (s_pfn_Set_File_SecurityA == NULL)
848 errno = ENOTSUP;
849 return FALSE;
851 filename_to_ansi (lpFileName, filename_a);
852 return (s_pfn_Set_File_SecurityA (filename_a, SecurityInformation,
853 pSecurityDescriptor));
857 static DWORD WINAPI
858 set_named_security_info (LPCTSTR lpObjectName,
859 SE_OBJECT_TYPE ObjectType,
860 SECURITY_INFORMATION SecurityInformation,
861 PSID psidOwner,
862 PSID psidGroup,
863 PACL pDacl,
864 PACL pSacl)
866 static SetNamedSecurityInfoW_Proc s_pfn_Set_Named_Security_InfoW = NULL;
867 static SetNamedSecurityInfoA_Proc s_pfn_Set_Named_Security_InfoA = NULL;
868 HMODULE hm_advapi32 = NULL;
869 if (is_windows_9x () == TRUE)
871 errno = ENOTSUP;
872 return ENOTSUP;
874 if (w32_unicode_filenames)
876 wchar_t filename_w[MAX_PATH];
878 if (g_b_init_set_named_security_info_w == 0)
880 g_b_init_set_named_security_info_w = 1;
881 hm_advapi32 = LoadLibrary ("Advapi32.dll");
882 s_pfn_Set_Named_Security_InfoW =
883 (SetNamedSecurityInfoW_Proc) GetProcAddress (hm_advapi32,
884 "SetNamedSecurityInfoW");
886 if (s_pfn_Set_Named_Security_InfoW == NULL)
888 errno = ENOTSUP;
889 return ENOTSUP;
891 filename_to_utf16 (lpObjectName, filename_w);
892 return (s_pfn_Set_Named_Security_InfoW (filename_w, ObjectType,
893 SecurityInformation, psidOwner,
894 psidGroup, pDacl, pSacl));
896 else
898 char filename_a[MAX_PATH];
900 if (g_b_init_set_named_security_info_a == 0)
902 g_b_init_set_named_security_info_a = 1;
903 hm_advapi32 = LoadLibrary ("Advapi32.dll");
904 s_pfn_Set_Named_Security_InfoA =
905 (SetNamedSecurityInfoA_Proc) GetProcAddress (hm_advapi32,
906 "SetNamedSecurityInfoA");
908 if (s_pfn_Set_Named_Security_InfoA == NULL)
910 errno = ENOTSUP;
911 return ENOTSUP;
913 filename_to_ansi (lpObjectName, filename_a);
914 return (s_pfn_Set_Named_Security_InfoA (filename_a, ObjectType,
915 SecurityInformation, psidOwner,
916 psidGroup, pDacl, pSacl));
920 static BOOL WINAPI
921 get_security_descriptor_owner (PSECURITY_DESCRIPTOR pSecurityDescriptor,
922 PSID *pOwner,
923 LPBOOL lpbOwnerDefaulted)
925 static GetSecurityDescriptorOwner_Proc s_pfn_Get_Security_Descriptor_Owner = NULL;
926 HMODULE hm_advapi32 = NULL;
927 if (is_windows_9x () == TRUE)
929 errno = ENOTSUP;
930 return FALSE;
932 if (g_b_init_get_security_descriptor_owner == 0)
934 g_b_init_get_security_descriptor_owner = 1;
935 hm_advapi32 = LoadLibrary ("Advapi32.dll");
936 s_pfn_Get_Security_Descriptor_Owner =
937 (GetSecurityDescriptorOwner_Proc) GetProcAddress (
938 hm_advapi32, "GetSecurityDescriptorOwner");
940 if (s_pfn_Get_Security_Descriptor_Owner == NULL)
942 errno = ENOTSUP;
943 return FALSE;
945 return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor, pOwner,
946 lpbOwnerDefaulted));
949 static BOOL WINAPI
950 get_security_descriptor_group (PSECURITY_DESCRIPTOR pSecurityDescriptor,
951 PSID *pGroup,
952 LPBOOL lpbGroupDefaulted)
954 static GetSecurityDescriptorGroup_Proc s_pfn_Get_Security_Descriptor_Group = NULL;
955 HMODULE hm_advapi32 = NULL;
956 if (is_windows_9x () == TRUE)
958 errno = ENOTSUP;
959 return FALSE;
961 if (g_b_init_get_security_descriptor_group == 0)
963 g_b_init_get_security_descriptor_group = 1;
964 hm_advapi32 = LoadLibrary ("Advapi32.dll");
965 s_pfn_Get_Security_Descriptor_Group =
966 (GetSecurityDescriptorGroup_Proc) GetProcAddress (
967 hm_advapi32, "GetSecurityDescriptorGroup");
969 if (s_pfn_Get_Security_Descriptor_Group == NULL)
971 errno = ENOTSUP;
972 return FALSE;
974 return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor, pGroup,
975 lpbGroupDefaulted));
978 static BOOL WINAPI
979 get_security_descriptor_dacl (PSECURITY_DESCRIPTOR pSecurityDescriptor,
980 LPBOOL lpbDaclPresent,
981 PACL *pDacl,
982 LPBOOL lpbDaclDefaulted)
984 static GetSecurityDescriptorDacl_Proc s_pfn_Get_Security_Descriptor_Dacl = NULL;
985 HMODULE hm_advapi32 = NULL;
986 if (is_windows_9x () == TRUE)
988 errno = ENOTSUP;
989 return FALSE;
991 if (g_b_init_get_security_descriptor_dacl == 0)
993 g_b_init_get_security_descriptor_dacl = 1;
994 hm_advapi32 = LoadLibrary ("Advapi32.dll");
995 s_pfn_Get_Security_Descriptor_Dacl =
996 (GetSecurityDescriptorDacl_Proc) GetProcAddress (
997 hm_advapi32, "GetSecurityDescriptorDacl");
999 if (s_pfn_Get_Security_Descriptor_Dacl == NULL)
1001 errno = ENOTSUP;
1002 return FALSE;
1004 return (s_pfn_Get_Security_Descriptor_Dacl (pSecurityDescriptor,
1005 lpbDaclPresent, pDacl,
1006 lpbDaclDefaulted));
1009 static BOOL WINAPI
1010 is_valid_sid (PSID sid)
1012 static IsValidSid_Proc s_pfn_Is_Valid_Sid = NULL;
1013 HMODULE hm_advapi32 = NULL;
1014 if (is_windows_9x () == TRUE)
1016 return FALSE;
1018 if (g_b_init_is_valid_sid == 0)
1020 g_b_init_is_valid_sid = 1;
1021 hm_advapi32 = LoadLibrary ("Advapi32.dll");
1022 s_pfn_Is_Valid_Sid =
1023 (IsValidSid_Proc) GetProcAddress (
1024 hm_advapi32, "IsValidSid");
1026 if (s_pfn_Is_Valid_Sid == NULL)
1028 return FALSE;
1030 return (s_pfn_Is_Valid_Sid (sid));
1033 static BOOL WINAPI
1034 equal_sid (PSID sid1, PSID sid2)
1036 static EqualSid_Proc s_pfn_Equal_Sid = NULL;
1037 HMODULE hm_advapi32 = NULL;
1038 if (is_windows_9x () == TRUE)
1040 return FALSE;
1042 if (g_b_init_equal_sid == 0)
1044 g_b_init_equal_sid = 1;
1045 hm_advapi32 = LoadLibrary ("Advapi32.dll");
1046 s_pfn_Equal_Sid =
1047 (EqualSid_Proc) GetProcAddress (
1048 hm_advapi32, "EqualSid");
1050 if (s_pfn_Equal_Sid == NULL)
1052 return FALSE;
1054 return (s_pfn_Equal_Sid (sid1, sid2));
1057 static DWORD WINAPI
1058 get_length_sid (PSID sid)
1060 static GetLengthSid_Proc s_pfn_Get_Length_Sid = NULL;
1061 HMODULE hm_advapi32 = NULL;
1062 if (is_windows_9x () == TRUE)
1064 return 0;
1066 if (g_b_init_get_length_sid == 0)
1068 g_b_init_get_length_sid = 1;
1069 hm_advapi32 = LoadLibrary ("Advapi32.dll");
1070 s_pfn_Get_Length_Sid =
1071 (GetLengthSid_Proc) GetProcAddress (
1072 hm_advapi32, "GetLengthSid");
1074 if (s_pfn_Get_Length_Sid == NULL)
1076 return 0;
1078 return (s_pfn_Get_Length_Sid (sid));
1081 static BOOL WINAPI
1082 copy_sid (DWORD destlen, PSID dest, PSID src)
1084 static CopySid_Proc s_pfn_Copy_Sid = NULL;
1085 HMODULE hm_advapi32 = NULL;
1086 if (is_windows_9x () == TRUE)
1088 return FALSE;
1090 if (g_b_init_copy_sid == 0)
1092 g_b_init_copy_sid = 1;
1093 hm_advapi32 = LoadLibrary ("Advapi32.dll");
1094 s_pfn_Copy_Sid =
1095 (CopySid_Proc) GetProcAddress (
1096 hm_advapi32, "CopySid");
1098 if (s_pfn_Copy_Sid == NULL)
1100 return FALSE;
1102 return (s_pfn_Copy_Sid (destlen, dest, src));
1106 END: Wrapper functions around OpenProcessToken
1107 and other functions in advapi32.dll that are only
1108 supported in Windows NT / 2k / XP
1111 static void WINAPI
1112 get_native_system_info (LPSYSTEM_INFO lpSystemInfo)
1114 static GetNativeSystemInfo_Proc s_pfn_Get_Native_System_Info = NULL;
1115 if (is_windows_9x () != TRUE)
1117 if (g_b_init_get_native_system_info == 0)
1119 g_b_init_get_native_system_info = 1;
1120 s_pfn_Get_Native_System_Info =
1121 (GetNativeSystemInfo_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1122 "GetNativeSystemInfo");
1124 if (s_pfn_Get_Native_System_Info != NULL)
1125 s_pfn_Get_Native_System_Info (lpSystemInfo);
1127 else
1128 lpSystemInfo->dwNumberOfProcessors = -1;
1131 static BOOL WINAPI
1132 get_system_times (LPFILETIME lpIdleTime,
1133 LPFILETIME lpKernelTime,
1134 LPFILETIME lpUserTime)
1136 static GetSystemTimes_Proc s_pfn_Get_System_times = NULL;
1137 if (is_windows_9x () == TRUE)
1139 return FALSE;
1141 if (g_b_init_get_system_times == 0)
1143 g_b_init_get_system_times = 1;
1144 s_pfn_Get_System_times =
1145 (GetSystemTimes_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1146 "GetSystemTimes");
1148 if (s_pfn_Get_System_times == NULL)
1149 return FALSE;
1150 return (s_pfn_Get_System_times (lpIdleTime, lpKernelTime, lpUserTime));
1153 static BOOLEAN WINAPI
1154 create_symbolic_link (LPCSTR lpSymlinkFilename,
1155 LPCSTR lpTargetFileName,
1156 DWORD dwFlags)
1158 static CreateSymbolicLinkW_Proc s_pfn_Create_Symbolic_LinkW = NULL;
1159 static CreateSymbolicLinkA_Proc s_pfn_Create_Symbolic_LinkA = NULL;
1160 BOOLEAN retval;
1162 if (is_windows_9x () == TRUE)
1164 errno = ENOSYS;
1165 return 0;
1167 if (w32_unicode_filenames)
1169 wchar_t symfn_w[MAX_PATH], tgtfn_w[MAX_PATH];
1171 if (g_b_init_create_symbolic_link_w == 0)
1173 g_b_init_create_symbolic_link_w = 1;
1174 s_pfn_Create_Symbolic_LinkW =
1175 (CreateSymbolicLinkW_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1176 "CreateSymbolicLinkW");
1178 if (s_pfn_Create_Symbolic_LinkW == NULL)
1180 errno = ENOSYS;
1181 return 0;
1184 filename_to_utf16 (lpSymlinkFilename, symfn_w);
1185 filename_to_utf16 (lpTargetFileName, tgtfn_w);
1186 retval = s_pfn_Create_Symbolic_LinkW (symfn_w, tgtfn_w, dwFlags);
1187 /* If we were denied creation of the symlink, try again after
1188 enabling the SeCreateSymbolicLinkPrivilege for our process. */
1189 if (!retval)
1191 TOKEN_PRIVILEGES priv_current;
1193 if (enable_privilege (SE_CREATE_SYMBOLIC_LINK_NAME, TRUE,
1194 &priv_current))
1196 retval = s_pfn_Create_Symbolic_LinkW (symfn_w, tgtfn_w, dwFlags);
1197 restore_privilege (&priv_current);
1198 revert_to_self ();
1202 else
1204 char symfn_a[MAX_PATH], tgtfn_a[MAX_PATH];
1206 if (g_b_init_create_symbolic_link_a == 0)
1208 g_b_init_create_symbolic_link_a = 1;
1209 s_pfn_Create_Symbolic_LinkA =
1210 (CreateSymbolicLinkA_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1211 "CreateSymbolicLinkA");
1213 if (s_pfn_Create_Symbolic_LinkA == NULL)
1215 errno = ENOSYS;
1216 return 0;
1219 filename_to_ansi (lpSymlinkFilename, symfn_a);
1220 filename_to_ansi (lpTargetFileName, tgtfn_a);
1221 retval = s_pfn_Create_Symbolic_LinkA (symfn_a, tgtfn_a, dwFlags);
1222 /* If we were denied creation of the symlink, try again after
1223 enabling the SeCreateSymbolicLinkPrivilege for our process. */
1224 if (!retval)
1226 TOKEN_PRIVILEGES priv_current;
1228 if (enable_privilege (SE_CREATE_SYMBOLIC_LINK_NAME, TRUE,
1229 &priv_current))
1231 retval = s_pfn_Create_Symbolic_LinkA (symfn_a, tgtfn_a, dwFlags);
1232 restore_privilege (&priv_current);
1233 revert_to_self ();
1237 return retval;
1240 static BOOL WINAPI
1241 is_valid_security_descriptor (PSECURITY_DESCRIPTOR pSecurityDescriptor)
1243 static IsValidSecurityDescriptor_Proc s_pfn_Is_Valid_Security_Descriptor_Proc = NULL;
1245 if (is_windows_9x () == TRUE)
1247 errno = ENOTSUP;
1248 return FALSE;
1251 if (g_b_init_is_valid_security_descriptor == 0)
1253 g_b_init_is_valid_security_descriptor = 1;
1254 s_pfn_Is_Valid_Security_Descriptor_Proc =
1255 (IsValidSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1256 "IsValidSecurityDescriptor");
1258 if (s_pfn_Is_Valid_Security_Descriptor_Proc == NULL)
1260 errno = ENOTSUP;
1261 return FALSE;
1264 return s_pfn_Is_Valid_Security_Descriptor_Proc (pSecurityDescriptor);
1267 static BOOL WINAPI
1268 convert_sd_to_sddl (PSECURITY_DESCRIPTOR SecurityDescriptor,
1269 DWORD RequestedStringSDRevision,
1270 SECURITY_INFORMATION SecurityInformation,
1271 LPTSTR *StringSecurityDescriptor,
1272 PULONG StringSecurityDescriptorLen)
1274 static ConvertSecurityDescriptorToStringSecurityDescriptor_Proc s_pfn_Convert_SD_To_SDDL = NULL;
1275 BOOL retval;
1277 if (is_windows_9x () == TRUE)
1279 errno = ENOTSUP;
1280 return FALSE;
1283 if (g_b_init_convert_sd_to_sddl == 0)
1285 g_b_init_convert_sd_to_sddl = 1;
1286 #ifdef _UNICODE
1287 s_pfn_Convert_SD_To_SDDL =
1288 (ConvertSecurityDescriptorToStringSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1289 "ConvertSecurityDescriptorToStringSecurityDescriptorW");
1290 #else
1291 s_pfn_Convert_SD_To_SDDL =
1292 (ConvertSecurityDescriptorToStringSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1293 "ConvertSecurityDescriptorToStringSecurityDescriptorA");
1294 #endif
1296 if (s_pfn_Convert_SD_To_SDDL == NULL)
1298 errno = ENOTSUP;
1299 return FALSE;
1302 retval = s_pfn_Convert_SD_To_SDDL (SecurityDescriptor,
1303 RequestedStringSDRevision,
1304 SecurityInformation,
1305 StringSecurityDescriptor,
1306 StringSecurityDescriptorLen);
1308 return retval;
1311 static BOOL WINAPI
1312 convert_sddl_to_sd (LPCTSTR StringSecurityDescriptor,
1313 DWORD StringSDRevision,
1314 PSECURITY_DESCRIPTOR *SecurityDescriptor,
1315 PULONG SecurityDescriptorSize)
1317 static ConvertStringSecurityDescriptorToSecurityDescriptor_Proc s_pfn_Convert_SDDL_To_SD = NULL;
1318 BOOL retval;
1320 if (is_windows_9x () == TRUE)
1322 errno = ENOTSUP;
1323 return FALSE;
1326 if (g_b_init_convert_sddl_to_sd == 0)
1328 g_b_init_convert_sddl_to_sd = 1;
1329 #ifdef _UNICODE
1330 s_pfn_Convert_SDDL_To_SD =
1331 (ConvertStringSecurityDescriptorToSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1332 "ConvertStringSecurityDescriptorToSecurityDescriptorW");
1333 #else
1334 s_pfn_Convert_SDDL_To_SD =
1335 (ConvertStringSecurityDescriptorToSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1336 "ConvertStringSecurityDescriptorToSecurityDescriptorA");
1337 #endif
1339 if (s_pfn_Convert_SDDL_To_SD == NULL)
1341 errno = ENOTSUP;
1342 return FALSE;
1345 retval = s_pfn_Convert_SDDL_To_SD (StringSecurityDescriptor,
1346 StringSDRevision,
1347 SecurityDescriptor,
1348 SecurityDescriptorSize);
1350 return retval;
1353 static DWORD WINAPI
1354 get_adapters_info (PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen)
1356 static GetAdaptersInfo_Proc s_pfn_Get_Adapters_Info = NULL;
1357 HMODULE hm_iphlpapi = NULL;
1359 if (is_windows_9x () == TRUE)
1360 return ERROR_NOT_SUPPORTED;
1362 if (g_b_init_get_adapters_info == 0)
1364 g_b_init_get_adapters_info = 1;
1365 hm_iphlpapi = LoadLibrary ("Iphlpapi.dll");
1366 if (hm_iphlpapi)
1367 s_pfn_Get_Adapters_Info = (GetAdaptersInfo_Proc)
1368 GetProcAddress (hm_iphlpapi, "GetAdaptersInfo");
1370 if (s_pfn_Get_Adapters_Info == NULL)
1371 return ERROR_NOT_SUPPORTED;
1372 return s_pfn_Get_Adapters_Info (pAdapterInfo, pOutBufLen);
1377 /* Return 1 if P is a valid pointer to an object of size SIZE. Return
1378 0 if P is NOT a valid pointer. Return -1 if we cannot validate P.
1380 This is called from alloc.c:valid_pointer_p. */
1382 w32_valid_pointer_p (void *p, int size)
1384 SIZE_T done;
1385 HANDLE h = OpenProcess (PROCESS_VM_READ, FALSE, GetCurrentProcessId ());
1387 if (h)
1389 unsigned char *buf = alloca (size);
1390 int retval = ReadProcessMemory (h, p, buf, size, &done);
1392 CloseHandle (h);
1393 return retval;
1395 else
1396 return -1;
1401 /* Here's an overview of how the Windows build supports file names
1402 that cannot be encoded by the current system codepage.
1404 From the POV of Lisp and layers of C code above the functions here,
1405 Emacs on Windows pretends that its file names are encoded in UTF-8;
1406 see encode_file and decode_file on coding.c. Any file name that is
1407 passed as a unibyte string to C functions defined here is assumed
1408 to be in UTF-8 encoding. Any file name returned by functions
1409 defined here must be in UTF-8 encoding, with only a few exceptions
1410 reserved for a couple of special cases. (Be sure to use
1411 MAX_UTF8_PATH for char arrays that store UTF-8 encoded file names,
1412 as they can be much longer than MAX_PATH!)
1414 The UTF-8 encoded file names cannot be passed to system APIs, as
1415 Windows does not support that. Therefore, they are converted
1416 either to UTF-16 or to the ANSI codepage, depending on the value of
1417 w32-unicode-filenames, before calling any system APIs or CRT library
1418 functions. The default value of that variable is determined by the
1419 OS on which Emacs runs: nil on Windows 9X and t otherwise, but the
1420 user can change that default (although I don't see why would she
1421 want to).
1423 The 4 functions defined below, filename_to_utf16, filename_to_ansi,
1424 filename_from_utf16, and filename_from_ansi, are the workhorses of
1425 these conversions. They rely on Windows native APIs
1426 MultiByteToWideChar and WideCharToMultiByte; we cannot use
1427 functions from coding.c here, because they allocate memory, which
1428 is a bad idea on the level of libc, which is what the functions
1429 here emulate. (If you worry about performance due to constant
1430 conversion back and forth from UTF-8 to UTF-16, then don't: first,
1431 it was measured to take only a few microseconds on a not-so-fast
1432 machine, and second, that's exactly what the ANSI APIs we used
1433 before did anyway, because they are just thin wrappers around the
1434 Unicode APIs.)
1436 The variables file-name-coding-system and default-file-name-coding-system
1437 still exist, but are actually used only when a file name needs to
1438 be converted to the ANSI codepage. This happens all the time when
1439 w32-unicode-filenames is nil, but can also happen from time to time
1440 when it is t. Otherwise, these variables have no effect on file-name
1441 encoding when w32-unicode-filenames is t; this is similar to
1442 selection-coding-system.
1444 This arrangement works very well, but it has a few gotchas and
1445 limitations:
1447 . Lisp code that encodes or decodes file names manually should
1448 normally use 'utf-8' as the coding-system on Windows,
1449 disregarding file-name-coding-system. This is a somewhat
1450 unpleasant consequence, but it cannot be avoided. Fortunately,
1451 very few Lisp packages need to do that.
1453 More generally, passing to library functions (e.g., fopen or
1454 opendir) file names already encoded in the ANSI codepage is
1455 explicitly *verboten*, as all those functions, as shadowed and
1456 emulated here, assume they will receive UTF-8 encoded file names.
1458 For the same reasons, no CRT function or Win32 API can be called
1459 directly in Emacs sources, without either converting the file
1460 names from UTF-8 to UTF-16 or ANSI codepage, or going through
1461 some shadowing function defined here.
1463 . Environment variables stored in Vprocess_environment are encoded
1464 in the ANSI codepage, so if getenv/egetenv is used for a variable
1465 whose value is a file name or a list of directories, it needs to
1466 be converted to UTF-8, before it is used as argument to functions
1467 or decoded into a Lisp string.
1469 . File names passed to external libraries, like the image libraries
1470 and GnuTLS, need special handling. These libraries generally
1471 don't support UTF-16 or UTF-8 file names, so they must get file
1472 names encoded in the ANSI codepage. To facilitate using these
1473 libraries with file names that are not encodable in the ANSI
1474 codepage, use the function ansi_encode_filename, which will try
1475 to use the short 8+3 alias of a file name if that file name is
1476 not encodable in the ANSI codepage. See image.c and gnutls.c for
1477 examples of how this should be done.
1479 . Running subprocesses in non-ASCII directories and with non-ASCII
1480 file arguments is limited to the current codepage (even though
1481 Emacs is perfectly capable of finding an executable program file
1482 in a directory whose name cannot be encoded in the current
1483 codepage). This is because the command-line arguments are
1484 encoded _before_ they get to the w32-specific level, and the
1485 encoding is not known in advance (it doesn't have to be the
1486 current ANSI codepage), so w32proc.c functions cannot re-encode
1487 them in UTF-16. This should be fixed, but will also require
1488 changes in cmdproxy. The current limitation is not terribly bad
1489 anyway, since very few, if any, Windows console programs that are
1490 likely to be invoked by Emacs support UTF-16 encoded command
1491 lines.
1493 . For similar reasons, server.el and emacsclient are also limited
1494 to the current ANSI codepage for now.
1496 . Emacs itself can only handle command-line arguments encoded in
1497 the current codepage.
1499 . Turning on w32-unicode-filename on Windows 9X (if it at all
1500 works) requires UNICOWS.DLL, which is thus a requirement even in
1501 non-GUI sessions, something the we previously avoided. */
1505 /* Converting file names from UTF-8 to either UTF-16 or the ANSI
1506 codepage defined by file-name-coding-system. */
1508 /* Current codepage for encoding file names. */
1509 static int file_name_codepage;
1511 /* Initialize the codepage used for decoding file names. This is
1512 needed to undo the value recorded during dumping, which might not
1513 be correct when we run the dumped Emacs. */
1514 void
1515 w32_init_file_name_codepage (void)
1517 file_name_codepage = CP_ACP;
1518 w32_ansi_code_page = CP_ACP;
1521 /* Produce a Windows ANSI codepage suitable for encoding file names.
1522 Return the information about that codepage in CP_INFO. */
1524 codepage_for_filenames (CPINFO *cp_info)
1526 /* A simple cache to avoid calling GetCPInfo every time we need to
1527 encode/decode a file name. The file-name encoding is not
1528 supposed to be changed too frequently, if ever. */
1529 static Lisp_Object last_file_name_encoding;
1530 static CPINFO cp;
1531 Lisp_Object current_encoding;
1533 current_encoding = Vfile_name_coding_system;
1534 if (NILP (current_encoding))
1535 current_encoding = Vdefault_file_name_coding_system;
1537 if (!EQ (last_file_name_encoding, current_encoding)
1538 || NILP (last_file_name_encoding))
1540 /* Default to the current ANSI codepage. */
1541 file_name_codepage = w32_ansi_code_page;
1543 if (!NILP (current_encoding))
1545 char *cpname = SSDATA (SYMBOL_NAME (current_encoding));
1546 char *cp = NULL, *end;
1547 int cpnum;
1549 if (strncmp (cpname, "cp", 2) == 0)
1550 cp = cpname + 2;
1551 else if (strncmp (cpname, "windows-", 8) == 0)
1552 cp = cpname + 8;
1554 if (cp)
1556 end = cp;
1557 cpnum = strtol (cp, &end, 10);
1558 if (cpnum && *end == '\0' && end - cp >= 2)
1559 file_name_codepage = cpnum;
1563 if (!file_name_codepage)
1564 file_name_codepage = CP_ACP; /* CP_ACP = 0, but let's not assume that */
1566 if (!GetCPInfo (file_name_codepage, &cp))
1568 file_name_codepage = CP_ACP;
1569 if (!GetCPInfo (file_name_codepage, &cp))
1570 emacs_abort ();
1573 /* Cache the new value. */
1574 last_file_name_encoding = current_encoding;
1576 if (cp_info)
1577 *cp_info = cp;
1579 return file_name_codepage;
1583 filename_to_utf16 (const char *fn_in, wchar_t *fn_out)
1585 int result = pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags, fn_in,
1586 -1, fn_out, MAX_PATH);
1588 if (!result)
1590 DWORD err = GetLastError ();
1592 switch (err)
1594 case ERROR_INVALID_FLAGS:
1595 case ERROR_INVALID_PARAMETER:
1596 errno = EINVAL;
1597 break;
1598 case ERROR_INSUFFICIENT_BUFFER:
1599 case ERROR_NO_UNICODE_TRANSLATION:
1600 default:
1601 errno = ENOENT;
1602 break;
1604 return -1;
1606 return 0;
1610 filename_from_utf16 (const wchar_t *fn_in, char *fn_out)
1612 int result = pWideCharToMultiByte (CP_UTF8, 0, fn_in, -1,
1613 fn_out, MAX_UTF8_PATH, NULL, NULL);
1615 if (!result)
1617 DWORD err = GetLastError ();
1619 switch (err)
1621 case ERROR_INVALID_FLAGS:
1622 case ERROR_INVALID_PARAMETER:
1623 errno = EINVAL;
1624 break;
1625 case ERROR_INSUFFICIENT_BUFFER:
1626 case ERROR_NO_UNICODE_TRANSLATION:
1627 default:
1628 errno = ENOENT;
1629 break;
1631 return -1;
1633 return 0;
1637 filename_to_ansi (const char *fn_in, char *fn_out)
1639 wchar_t fn_utf16[MAX_PATH];
1641 if (filename_to_utf16 (fn_in, fn_utf16) == 0)
1643 int result;
1644 int codepage = codepage_for_filenames (NULL);
1646 result = pWideCharToMultiByte (codepage, 0, fn_utf16, -1,
1647 fn_out, MAX_PATH, NULL, NULL);
1648 if (!result)
1650 DWORD err = GetLastError ();
1652 switch (err)
1654 case ERROR_INVALID_FLAGS:
1655 case ERROR_INVALID_PARAMETER:
1656 errno = EINVAL;
1657 break;
1658 case ERROR_INSUFFICIENT_BUFFER:
1659 case ERROR_NO_UNICODE_TRANSLATION:
1660 default:
1661 errno = ENOENT;
1662 break;
1664 return -1;
1666 return 0;
1668 return -1;
1672 filename_from_ansi (const char *fn_in, char *fn_out)
1674 wchar_t fn_utf16[MAX_PATH];
1675 int codepage = codepage_for_filenames (NULL);
1676 int result = pMultiByteToWideChar (codepage, multiByteToWideCharFlags, fn_in,
1677 -1, fn_utf16, MAX_PATH);
1679 if (!result)
1681 DWORD err = GetLastError ();
1683 switch (err)
1685 case ERROR_INVALID_FLAGS:
1686 case ERROR_INVALID_PARAMETER:
1687 errno = EINVAL;
1688 break;
1689 case ERROR_INSUFFICIENT_BUFFER:
1690 case ERROR_NO_UNICODE_TRANSLATION:
1691 default:
1692 errno = ENOENT;
1693 break;
1695 return -1;
1697 return filename_from_utf16 (fn_utf16, fn_out);
1702 /* The directory where we started, in UTF-8. */
1703 static char startup_dir[MAX_UTF8_PATH];
1705 /* Get the current working directory. */
1706 char *
1707 getcwd (char *dir, int dirsize)
1709 if (!dirsize)
1711 errno = EINVAL;
1712 return NULL;
1714 if (dirsize <= strlen (startup_dir))
1716 errno = ERANGE;
1717 return NULL;
1719 #if 0
1720 if (GetCurrentDirectory (MAXPATHLEN, dir) > 0)
1721 return dir;
1722 return NULL;
1723 #else
1724 /* Emacs doesn't actually change directory itself, it stays in the
1725 same directory where it was started. */
1726 strcpy (dir, startup_dir);
1727 return dir;
1728 #endif
1731 /* Emulate getloadavg. */
1733 struct load_sample {
1734 time_t sample_time;
1735 ULONGLONG idle;
1736 ULONGLONG kernel;
1737 ULONGLONG user;
1740 /* Number of processors on this machine. */
1741 static unsigned num_of_processors;
1743 /* We maintain 1-sec samples for the last 16 minutes in a circular buffer. */
1744 static struct load_sample samples[16*60];
1745 static int first_idx = -1, last_idx = -1;
1746 static int max_idx = ARRAYELTS (samples);
1748 static int
1749 buf_next (int from)
1751 int next_idx = from + 1;
1753 if (next_idx >= max_idx)
1754 next_idx = 0;
1756 return next_idx;
1759 static int
1760 buf_prev (int from)
1762 int prev_idx = from - 1;
1764 if (prev_idx < 0)
1765 prev_idx = max_idx - 1;
1767 return prev_idx;
1770 static void
1771 sample_system_load (ULONGLONG *idle, ULONGLONG *kernel, ULONGLONG *user)
1773 SYSTEM_INFO sysinfo;
1774 FILETIME ft_idle, ft_user, ft_kernel;
1776 /* Initialize the number of processors on this machine. */
1777 if (num_of_processors <= 0)
1779 get_native_system_info (&sysinfo);
1780 num_of_processors = sysinfo.dwNumberOfProcessors;
1781 if (num_of_processors <= 0)
1783 GetSystemInfo (&sysinfo);
1784 num_of_processors = sysinfo.dwNumberOfProcessors;
1786 if (num_of_processors <= 0)
1787 num_of_processors = 1;
1790 /* TODO: Take into account threads that are ready to run, by
1791 sampling the "\System\Processor Queue Length" performance
1792 counter. The code below accounts only for threads that are
1793 actually running. */
1795 if (get_system_times (&ft_idle, &ft_kernel, &ft_user))
1797 ULARGE_INTEGER uidle, ukernel, uuser;
1799 memcpy (&uidle, &ft_idle, sizeof (ft_idle));
1800 memcpy (&ukernel, &ft_kernel, sizeof (ft_kernel));
1801 memcpy (&uuser, &ft_user, sizeof (ft_user));
1802 *idle = uidle.QuadPart;
1803 *kernel = ukernel.QuadPart;
1804 *user = uuser.QuadPart;
1806 else
1808 *idle = 0;
1809 *kernel = 0;
1810 *user = 0;
1814 /* Produce the load average for a given time interval, using the
1815 samples in the samples[] array. WHICH can be 0, 1, or 2, meaning
1816 1-minute, 5-minute, or 15-minute average, respectively. */
1817 static double
1818 getavg (int which)
1820 double retval = -1.0;
1821 double tdiff;
1822 int idx;
1823 double span = (which == 0 ? 1.0 : (which == 1 ? 5.0 : 15.0)) * 60;
1824 time_t now = samples[last_idx].sample_time;
1826 if (first_idx != last_idx)
1828 for (idx = buf_prev (last_idx); ; idx = buf_prev (idx))
1830 tdiff = difftime (now, samples[idx].sample_time);
1831 if (tdiff >= span - 2*DBL_EPSILON*now)
1833 long double sys =
1834 samples[last_idx].kernel + samples[last_idx].user
1835 - (samples[idx].kernel + samples[idx].user);
1836 long double idl = samples[last_idx].idle - samples[idx].idle;
1838 retval = (1.0 - idl / sys) * num_of_processors;
1839 break;
1841 if (idx == first_idx)
1842 break;
1846 return retval;
1850 getloadavg (double loadavg[], int nelem)
1852 int elem;
1853 ULONGLONG idle, kernel, user;
1854 time_t now = time (NULL);
1856 /* If system time jumped back for some reason, delete all samples
1857 whose time is later than the current wall-clock time. This
1858 prevents load average figures from becoming frozen for prolonged
1859 periods of time, when system time is reset backwards. */
1860 if (last_idx >= 0)
1862 while (difftime (now, samples[last_idx].sample_time) < -1.0)
1864 if (last_idx == first_idx)
1866 first_idx = last_idx = -1;
1867 break;
1869 last_idx = buf_prev (last_idx);
1873 /* Store another sample. We ignore samples that are less than 1 sec
1874 apart. */
1875 if (last_idx < 0
1876 || (difftime (now, samples[last_idx].sample_time)
1877 >= 1.0 - 2*DBL_EPSILON*now))
1879 sample_system_load (&idle, &kernel, &user);
1880 last_idx = buf_next (last_idx);
1881 samples[last_idx].sample_time = now;
1882 samples[last_idx].idle = idle;
1883 samples[last_idx].kernel = kernel;
1884 samples[last_idx].user = user;
1885 /* If the buffer has more that 15 min worth of samples, discard
1886 the old ones. */
1887 if (first_idx == -1)
1888 first_idx = last_idx;
1889 while (first_idx != last_idx
1890 && (difftime (now, samples[first_idx].sample_time)
1891 >= 15.0*60 + 2*DBL_EPSILON*now))
1892 first_idx = buf_next (first_idx);
1895 for (elem = 0; elem < nelem; elem++)
1897 double avg = getavg (elem);
1899 if (avg < 0)
1900 break;
1901 loadavg[elem] = avg;
1904 return elem;
1907 /* Emulate getpwuid, getpwnam and others. */
1909 #define PASSWD_FIELD_SIZE 256
1911 static char dflt_passwd_name[PASSWD_FIELD_SIZE];
1912 static char dflt_passwd_passwd[PASSWD_FIELD_SIZE];
1913 static char dflt_passwd_gecos[PASSWD_FIELD_SIZE];
1914 static char dflt_passwd_dir[MAX_UTF8_PATH];
1915 static char dflt_passwd_shell[MAX_UTF8_PATH];
1917 static struct passwd dflt_passwd =
1919 dflt_passwd_name,
1920 dflt_passwd_passwd,
1924 dflt_passwd_gecos,
1925 dflt_passwd_dir,
1926 dflt_passwd_shell,
1929 static char dflt_group_name[GNLEN+1];
1931 static struct group dflt_group =
1933 /* When group information is not available, we return this as the
1934 group for all files. */
1935 dflt_group_name,
1939 unsigned
1940 getuid (void)
1942 return dflt_passwd.pw_uid;
1945 unsigned
1946 geteuid (void)
1948 /* I could imagine arguing for checking to see whether the user is
1949 in the Administrators group and returning a UID of 0 for that
1950 case, but I don't know how wise that would be in the long run. */
1951 return getuid ();
1954 unsigned
1955 getgid (void)
1957 return dflt_passwd.pw_gid;
1960 unsigned
1961 getegid (void)
1963 return getgid ();
1966 struct passwd *
1967 getpwuid (unsigned uid)
1969 if (uid == dflt_passwd.pw_uid)
1970 return &dflt_passwd;
1971 return NULL;
1974 struct group *
1975 getgrgid (gid_t gid)
1977 return &dflt_group;
1980 struct passwd *
1981 getpwnam (char *name)
1983 struct passwd *pw;
1985 pw = getpwuid (getuid ());
1986 if (!pw)
1987 return pw;
1989 if (xstrcasecmp (name, pw->pw_name))
1990 return NULL;
1992 return pw;
1995 static void
1996 init_user_info (void)
1998 /* Find the user's real name by opening the process token and
1999 looking up the name associated with the user-sid in that token.
2001 Use the relative portion of the identifier authority value from
2002 the user-sid as the user id value (same for group id using the
2003 primary group sid from the process token). */
2005 char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
2006 DWORD ulength = sizeof (uname), dlength = sizeof (domain), needed;
2007 DWORD glength = sizeof (gname);
2008 HANDLE token = NULL;
2009 SID_NAME_USE user_type;
2010 unsigned char *buf = NULL;
2011 DWORD blen = 0;
2012 TOKEN_USER user_token;
2013 TOKEN_PRIMARY_GROUP group_token;
2014 BOOL result;
2016 result = open_process_token (GetCurrentProcess (), TOKEN_QUERY, &token);
2017 if (result)
2019 result = get_token_information (token, TokenUser, NULL, 0, &blen);
2020 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
2022 buf = xmalloc (blen);
2023 result = get_token_information (token, TokenUser,
2024 (LPVOID)buf, blen, &needed);
2025 if (result)
2027 memcpy (&user_token, buf, sizeof (user_token));
2028 result = lookup_account_sid (NULL, user_token.User.Sid,
2029 uname, &ulength,
2030 domain, &dlength, &user_type);
2033 else
2034 result = FALSE;
2036 if (result)
2038 strcpy (dflt_passwd.pw_name, uname);
2039 /* Determine a reasonable uid value. */
2040 if (xstrcasecmp ("administrator", uname) == 0)
2042 dflt_passwd.pw_uid = 500; /* well-known Administrator uid */
2043 dflt_passwd.pw_gid = 513; /* well-known None gid */
2045 else
2047 /* Use the last sub-authority value of the RID, the relative
2048 portion of the SID, as user/group ID. */
2049 dflt_passwd.pw_uid = get_rid (user_token.User.Sid);
2051 /* Get group id and name. */
2052 result = get_token_information (token, TokenPrimaryGroup,
2053 (LPVOID)buf, blen, &needed);
2054 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
2056 buf = xrealloc (buf, blen = needed);
2057 result = get_token_information (token, TokenPrimaryGroup,
2058 (LPVOID)buf, blen, &needed);
2060 if (result)
2062 memcpy (&group_token, buf, sizeof (group_token));
2063 dflt_passwd.pw_gid = get_rid (group_token.PrimaryGroup);
2064 dlength = sizeof (domain);
2065 /* If we can get at the real Primary Group name, use that.
2066 Otherwise, the default group name was already set to
2067 "None" in globals_of_w32. */
2068 if (lookup_account_sid (NULL, group_token.PrimaryGroup,
2069 gname, &glength, NULL, &dlength,
2070 &user_type))
2071 strcpy (dflt_group_name, gname);
2073 else
2074 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
2077 /* If security calls are not supported (presumably because we
2078 are running under Windows 9X), fallback to this: */
2079 else if (GetUserName (uname, &ulength))
2081 strcpy (dflt_passwd.pw_name, uname);
2082 if (xstrcasecmp ("administrator", uname) == 0)
2083 dflt_passwd.pw_uid = 0;
2084 else
2085 dflt_passwd.pw_uid = 123;
2086 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
2088 else
2090 strcpy (dflt_passwd.pw_name, "unknown");
2091 dflt_passwd.pw_uid = 123;
2092 dflt_passwd.pw_gid = 123;
2094 dflt_group.gr_gid = dflt_passwd.pw_gid;
2096 /* Set dir and shell from environment variables. */
2097 if (w32_unicode_filenames)
2099 wchar_t *home = _wgetenv (L"HOME");
2100 wchar_t *shell = _wgetenv (L"SHELL");
2102 /* Ensure HOME and SHELL are defined. */
2103 if (home == NULL)
2104 emacs_abort ();
2105 if (shell == NULL)
2106 emacs_abort ();
2107 filename_from_utf16 (home, dflt_passwd.pw_dir);
2108 filename_from_utf16 (shell, dflt_passwd.pw_shell);
2110 else
2112 char *home = getenv ("HOME");
2113 char *shell = getenv ("SHELL");
2115 if (home == NULL)
2116 emacs_abort ();
2117 if (shell == NULL)
2118 emacs_abort ();
2119 filename_from_ansi (home, dflt_passwd.pw_dir);
2120 filename_from_ansi (shell, dflt_passwd.pw_shell);
2123 xfree (buf);
2124 if (token)
2125 CloseHandle (token);
2128 static HCRYPTPROV w32_crypto_hprov;
2129 static int
2130 w32_init_crypt_random (void)
2132 if (!CryptAcquireContext (&w32_crypto_hprov, NULL, NULL, PROV_RSA_FULL,
2133 CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
2135 DebPrint (("CryptAcquireContext failed with error %x\n",
2136 GetLastError ()));
2137 w32_crypto_hprov = 0;
2138 return -1;
2140 return 0;
2144 w32_init_random (void *buf, ptrdiff_t buflen)
2146 if (!w32_crypto_hprov)
2147 w32_init_crypt_random ();
2148 if (w32_crypto_hprov)
2150 if (CryptGenRandom (w32_crypto_hprov, buflen, (BYTE *)buf))
2151 return 0;
2153 return -1;
2156 /* MS-Windows 'rand' produces separate identical series for each
2157 thread, so we replace it with our version. */
2159 /* Algorithm AS183: An Efficient and Portable Pseudo-random Number
2160 Generator, by B.A. Wichmann, I.D. Hill. AS, v31, No. 2 (1982). */
2161 static int ix = 3172, iy = 9814, iz = 20125;
2162 #define RAND_MAX_X 30269
2163 #define RAND_MAX_Y 30307
2164 #define RAND_MAX_Z 30323
2166 static int
2167 rand_as183 (void)
2169 ix = (171 * ix) % RAND_MAX_X;
2170 iy = (172 * iy) % RAND_MAX_Y;
2171 iz = (170 * iz) % RAND_MAX_Z;
2173 return (ix + iy + iz) & 0x7fff;
2177 random (void)
2179 /* rand_as183 () gives us 15 random bits...hack together 30 bits. */
2180 return ((rand_as183 () << 15) | rand_as183 ());
2183 void
2184 srandom (int seed)
2186 srand (seed);
2187 ix = rand () % RAND_MAX_X;
2188 iy = rand () % RAND_MAX_Y;
2189 iz = rand () % RAND_MAX_Z;
2192 /* Return the maximum length in bytes of a multibyte character
2193 sequence encoded in the current ANSI codepage. This is required to
2194 correctly walk the encoded file names one character at a time. */
2195 static int
2196 max_filename_mbslen (void)
2198 CPINFO cp_info;
2200 codepage_for_filenames (&cp_info);
2201 return cp_info.MaxCharSize;
2204 /* Normalize filename by converting in-place all of its path
2205 separators to the separator specified by PATH_SEP. */
2207 static void
2208 normalize_filename (register char *fp, char path_sep)
2210 char *p2;
2212 /* Always lower-case drive letters a-z, even if the filesystem
2213 preserves case in filenames.
2214 This is so filenames can be compared by string comparison
2215 functions that are case-sensitive. Even case-preserving filesystems
2216 do not distinguish case in drive letters. */
2217 p2 = fp + 1;
2219 if (*p2 == ':' && *fp >= 'A' && *fp <= 'Z')
2221 *fp += 'a' - 'A';
2222 fp += 2;
2225 while (*fp)
2227 if ((*fp == '/' || *fp == '\\') && *fp != path_sep)
2228 *fp = path_sep;
2229 fp++;
2233 /* Destructively turn backslashes into slashes. */
2234 void
2235 dostounix_filename (register char *p)
2237 normalize_filename (p, '/');
2240 /* Destructively turn slashes into backslashes. */
2241 void
2242 unixtodos_filename (register char *p)
2244 normalize_filename (p, '\\');
2247 /* Remove all CR's that are followed by a LF.
2248 (From msdos.c...probably should figure out a way to share it,
2249 although this code isn't going to ever change.) */
2250 static int
2251 crlf_to_lf (register int n, register char *buf)
2253 unsigned char *np = (unsigned char *)buf;
2254 unsigned char *startp = np;
2255 char *endp = buf + n;
2257 if (n == 0)
2258 return n;
2259 while (buf < endp - 1)
2261 if (*buf == 0x0d)
2263 if (*(++buf) != 0x0a)
2264 *np++ = 0x0d;
2266 else
2267 *np++ = *buf++;
2269 if (buf < endp)
2270 *np++ = *buf++;
2271 return np - startp;
2274 /* Parse the root part of file name, if present. Return length and
2275 optionally store pointer to char after root. */
2276 static int
2277 parse_root (const char * name, const char ** pPath)
2279 const char * start = name;
2281 if (name == NULL)
2282 return 0;
2284 /* find the root name of the volume if given */
2285 if (isalpha (name[0]) && name[1] == ':')
2287 /* skip past drive specifier */
2288 name += 2;
2289 if (IS_DIRECTORY_SEP (name[0]))
2290 name++;
2292 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
2294 int slashes = 2;
2296 name += 2;
2299 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
2300 break;
2301 name++;
2303 while ( *name );
2304 if (IS_DIRECTORY_SEP (name[0]))
2305 name++;
2308 if (pPath)
2309 *pPath = name;
2311 return name - start;
2314 /* Get long base name for name; name is assumed to be absolute. */
2315 static int
2316 get_long_basename (char * name, char * buf, int size)
2318 HANDLE dir_handle = INVALID_HANDLE_VALUE;
2319 char fname_utf8[MAX_UTF8_PATH];
2320 int len = 0;
2321 int cstatus = -1;
2323 /* Must be valid filename, no wild cards or other invalid characters. */
2324 if (strpbrk (name, "*?|<>\""))
2325 return 0;
2327 if (w32_unicode_filenames)
2329 wchar_t fname_utf16[MAX_PATH];
2330 WIN32_FIND_DATAW find_data_wide;
2332 filename_to_utf16 (name, fname_utf16);
2333 dir_handle = FindFirstFileW (fname_utf16, &find_data_wide);
2334 if (dir_handle != INVALID_HANDLE_VALUE)
2335 cstatus = filename_from_utf16 (find_data_wide.cFileName, fname_utf8);
2337 else
2339 char fname_ansi[MAX_PATH];
2340 WIN32_FIND_DATAA find_data_ansi;
2342 filename_to_ansi (name, fname_ansi);
2343 /* If the ANSI name includes ? characters, it is not encodable
2344 in the ANSI codepage. In that case, we deliver the question
2345 marks to the caller; calling FindFirstFileA in this case
2346 could return some unrelated file name in the same
2347 directory. */
2348 if (_mbspbrk (fname_ansi, "?"))
2350 /* Find the basename of fname_ansi. */
2351 char *p = strrchr (fname_ansi, '\\');
2353 if (!p)
2354 p = fname_ansi;
2355 else
2356 p++;
2357 cstatus = filename_from_ansi (p, fname_utf8);
2359 else
2361 dir_handle = FindFirstFileA (fname_ansi, &find_data_ansi);
2362 if (dir_handle != INVALID_HANDLE_VALUE)
2363 cstatus = filename_from_ansi (find_data_ansi.cFileName, fname_utf8);
2367 if (cstatus == 0 && (len = strlen (fname_utf8)) < size)
2368 memcpy (buf, fname_utf8, len + 1);
2369 else
2370 len = 0;
2372 if (dir_handle != INVALID_HANDLE_VALUE)
2373 FindClose (dir_handle);
2375 return len;
2378 /* Get long name for file, if possible (assumed to be absolute). */
2379 BOOL
2380 w32_get_long_filename (const char * name, char * buf, int size)
2382 char * o = buf;
2383 char * p;
2384 const char * q;
2385 char full[ MAX_UTF8_PATH ];
2386 int len;
2388 len = strlen (name);
2389 if (len >= MAX_UTF8_PATH)
2390 return FALSE;
2392 /* Use local copy for destructive modification. */
2393 memcpy (full, name, len+1);
2394 unixtodos_filename (full);
2396 /* Copy root part verbatim. */
2397 len = parse_root (full, (const char **)&p);
2398 memcpy (o, full, len);
2399 o += len;
2400 *o = '\0';
2401 size -= len;
2403 while (p != NULL && *p)
2405 q = p;
2406 p = strchr (q, '\\');
2407 if (p) *p = '\0';
2408 len = get_long_basename (full, o, size);
2409 if (len > 0)
2411 o += len;
2412 size -= len;
2413 if (p != NULL)
2415 *p++ = '\\';
2416 if (size < 2)
2417 return FALSE;
2418 *o++ = '\\';
2419 size--;
2420 *o = '\0';
2423 else
2424 return FALSE;
2427 return TRUE;
2430 unsigned int
2431 w32_get_short_filename (const char * name, char * buf, int size)
2433 if (w32_unicode_filenames)
2435 wchar_t name_utf16[MAX_PATH], short_name[MAX_PATH];
2436 unsigned int retval;
2438 filename_to_utf16 (name, name_utf16);
2439 retval = GetShortPathNameW (name_utf16, short_name, size);
2440 if (retval && retval < size)
2441 filename_from_utf16 (short_name, buf);
2442 return retval;
2444 else
2446 char name_ansi[MAX_PATH];
2448 filename_to_ansi (name, name_ansi);
2449 return GetShortPathNameA (name_ansi, buf, size);
2453 /* Re-encode FILENAME, a UTF-8 encoded unibyte string, using the
2454 MS-Windows ANSI codepage. If FILENAME includes characters not
2455 supported by the ANSI codepage, return the 8+3 alias of FILENAME,
2456 if it exists. This is needed because the w32 build wants to
2457 support file names outside of the system locale, but image
2458 libraries typically don't support wide (a.k.a. "Unicode") APIs
2459 required for that. */
2461 Lisp_Object
2462 ansi_encode_filename (Lisp_Object filename)
2464 Lisp_Object encoded_filename;
2465 char fname[MAX_PATH];
2467 filename_to_ansi (SSDATA (filename), fname);
2468 if (_mbspbrk (fname, "?"))
2470 char shortname[MAX_PATH];
2472 if (w32_get_short_filename (SSDATA (filename), shortname, MAX_PATH))
2474 dostounix_filename (shortname);
2475 encoded_filename = build_string (shortname);
2477 else
2478 encoded_filename = build_unibyte_string (fname);
2480 else
2481 encoded_filename = build_unibyte_string (fname);
2482 return encoded_filename;
2485 static int
2486 is_unc_volume (const char *filename)
2488 const char *ptr = filename;
2490 if (!IS_DIRECTORY_SEP (ptr[0]) || !IS_DIRECTORY_SEP (ptr[1]) || !ptr[2])
2491 return 0;
2493 if (strpbrk (ptr + 2, "*?|<>\"\\/"))
2494 return 0;
2496 return 1;
2499 /* Emulate the Posix unsetenv. */
2501 unsetenv (const char *name)
2503 char *var;
2504 size_t name_len;
2506 if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
2508 errno = EINVAL;
2509 return -1;
2511 name_len = strlen (name);
2512 /* MS docs says an environment variable cannot be longer than 32K. */
2513 if (name_len > 32767)
2515 errno = ENOMEM;
2516 return 0;
2518 /* It is safe to use 'alloca' with 32K size, since the stack is at
2519 least 2MB, and we set it to 8MB in the link command line. */
2520 var = alloca (name_len + 2);
2521 strncpy (var, name, name_len);
2522 var[name_len++] = '=';
2523 var[name_len] = '\0';
2524 return _putenv (var);
2527 /* MS _putenv doesn't support removing a variable when the argument
2528 does not include the '=' character, so we fix that here. */
2530 sys_putenv (char *str)
2532 const char *const name_end = strchr (str, '=');
2534 if (name_end == NULL)
2536 /* Remove the variable from the environment. */
2537 return unsetenv (str);
2540 if (strncmp (str, "TZ=<", 4) == 0)
2542 /* MS-Windows does not support POSIX.1-2001 angle-bracket TZ
2543 abbreviation syntax. Convert to POSIX.1-1988 syntax if possible,
2544 and to the undocumented placeholder "ZZZ" otherwise. */
2545 bool supported_abbr = true;
2546 for (char *p = str + 4; *p; p++)
2548 if (('0' <= *p && *p <= '9') || *p == '-' || *p == '+')
2549 supported_abbr = false;
2550 else if (*p == '>')
2552 ptrdiff_t abbrlen;
2553 if (supported_abbr)
2555 abbrlen = p - (str + 4);
2556 memmove (str + 3, str + 4, abbrlen);
2558 else
2560 abbrlen = 3;
2561 memset (str + 3, 'Z', abbrlen);
2563 memmove (str + 3 + abbrlen, p + 1, strlen (p));
2564 break;
2569 return _putenv (str);
2572 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
2574 LPBYTE
2575 w32_get_resource (const char *key, LPDWORD lpdwtype)
2577 LPBYTE lpvalue;
2578 HKEY hrootkey = NULL;
2579 DWORD cbData;
2581 /* Check both the current user and the local machine to see if
2582 we have any resources. */
2584 if (RegOpenKeyEx (HKEY_CURRENT_USER, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
2586 lpvalue = NULL;
2588 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
2589 && (lpvalue = xmalloc (cbData)) != NULL
2590 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
2592 RegCloseKey (hrootkey);
2593 return (lpvalue);
2596 xfree (lpvalue);
2598 RegCloseKey (hrootkey);
2601 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
2603 lpvalue = NULL;
2605 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
2606 && (lpvalue = xmalloc (cbData)) != NULL
2607 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
2609 RegCloseKey (hrootkey);
2610 return (lpvalue);
2613 xfree (lpvalue);
2615 RegCloseKey (hrootkey);
2618 return (NULL);
2621 /* The argv[] array holds ANSI-encoded strings, and so this function
2622 works with ANS_encoded strings. */
2623 void
2624 init_environment (char ** argv)
2626 static const char * const tempdirs[] = {
2627 "$TMPDIR", "$TEMP", "$TMP", "c:/"
2630 int i;
2632 const int imax = ARRAYELTS (tempdirs);
2634 /* Implementation note: This function explicitly works with ANSI
2635 file names, not with UTF-8 encoded file names. This is because
2636 this function pushes variables into the Emacs's environment, and
2637 the environment variables are always assumed to be in the
2638 locale-specific encoding. Do NOT call any functions that accept
2639 UTF-8 file names from this function! */
2641 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
2642 temporary files and assume "/tmp" if $TMPDIR is unset, which
2643 will break on DOS/Windows. Refuse to work if we cannot find
2644 a directory, not even "c:/", usable for that purpose. */
2645 for (i = 0; i < imax ; i++)
2647 const char *tmp = tempdirs[i];
2649 if (*tmp == '$')
2650 tmp = getenv (tmp + 1);
2651 /* Note that `access' can lie to us if the directory resides on a
2652 read-only filesystem, like CD-ROM or a write-protected floppy.
2653 The only way to be really sure is to actually create a file and
2654 see if it succeeds. But I think that's too much to ask. */
2656 /* MSVCRT's _access crashes with D_OK, so we use our replacement. */
2657 if (tmp && sys_access (tmp, D_OK) == 0)
2659 char * var = alloca (strlen (tmp) + 8);
2660 sprintf (var, "TMPDIR=%s", tmp);
2661 _putenv (strdup (var));
2662 break;
2665 if (i >= imax)
2666 cmd_error_internal
2667 (Fcons (Qerror,
2668 Fcons (build_string ("no usable temporary directories found!!"),
2669 Qnil)),
2670 "While setting TMPDIR: ");
2672 /* Check for environment variables and use registry settings if they
2673 don't exist. Fallback on default values where applicable. */
2675 int i;
2676 LPBYTE lpval;
2677 DWORD dwType;
2678 char locale_name[32];
2679 char default_home[MAX_PATH];
2680 int appdata = 0;
2682 static const struct env_entry
2684 const char * name;
2685 const char * def_value;
2686 } dflt_envvars[] =
2688 /* If the default value is NULL, we will use the value from the
2689 outside environment or the Registry, but will not push the
2690 variable into the Emacs environment if it is defined neither
2691 in the Registry nor in the outside environment. */
2692 {"HOME", "C:/"},
2693 {"PRELOAD_WINSOCK", NULL},
2694 {"emacs_dir", "C:/emacs"},
2695 {"EMACSLOADPATH", NULL},
2696 {"SHELL", "cmdproxy.exe"}, /* perhaps it is somewhere on PATH */
2697 {"EMACSDATA", NULL},
2698 {"EMACSPATH", NULL},
2699 {"INFOPATH", NULL},
2700 {"EMACSDOC", NULL},
2701 {"TERM", "cmd"},
2702 {"LANG", NULL},
2705 #define N_ENV_VARS ARRAYELTS (dflt_envvars)
2707 /* We need to copy dflt_envvars[] and work on the copy because we
2708 don't want the dumped Emacs to inherit the values of
2709 environment variables we saw during dumping (which could be on
2710 a different system). The defaults above must be left intact. */
2711 struct env_entry env_vars[N_ENV_VARS];
2713 for (i = 0; i < N_ENV_VARS; i++)
2714 env_vars[i] = dflt_envvars[i];
2716 /* For backwards compatibility, check if a .emacs file exists in C:/
2717 If not, then we can try to default to the appdata directory under the
2718 user's profile, which is more likely to be writable. */
2719 if (sys_access ("C:/.emacs", F_OK) != 0)
2721 HRESULT profile_result;
2722 /* Dynamically load ShGetFolderPath, as it won't exist on versions
2723 of Windows 95 and NT4 that have not been updated to include
2724 MSIE 5. */
2725 ShGetFolderPath_fn get_folder_path;
2726 get_folder_path = (ShGetFolderPath_fn)
2727 GetProcAddress (GetModuleHandle ("shell32.dll"), "SHGetFolderPathA");
2729 if (get_folder_path != NULL)
2731 profile_result = get_folder_path (NULL, CSIDL_APPDATA, NULL,
2732 0, default_home);
2734 /* If we can't get the appdata dir, revert to old behavior. */
2735 if (profile_result == S_OK)
2737 env_vars[0].def_value = default_home;
2738 appdata = 1;
2743 /* Get default locale info and use it for LANG. */
2744 if (GetLocaleInfo (LOCALE_USER_DEFAULT,
2745 LOCALE_SABBREVLANGNAME | LOCALE_USE_CP_ACP,
2746 locale_name, sizeof (locale_name)))
2748 for (i = 0; i < N_ENV_VARS; i++)
2750 if (strcmp (env_vars[i].name, "LANG") == 0)
2752 env_vars[i].def_value = locale_name;
2753 break;
2758 #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
2760 /* Treat emacs_dir specially: set it unconditionally based on our
2761 location. */
2763 char *p;
2764 char modname[MAX_PATH];
2766 if (!GetModuleFileNameA (NULL, modname, MAX_PATH))
2767 emacs_abort ();
2768 if ((p = _mbsrchr (modname, '\\')) == NULL)
2769 emacs_abort ();
2770 *p = 0;
2772 if ((p = _mbsrchr (modname, '\\'))
2773 /* From bin means installed Emacs, from src means uninstalled. */
2774 && (xstrcasecmp (p, "\\bin") == 0 || xstrcasecmp (p, "\\src") == 0))
2776 char buf[SET_ENV_BUF_SIZE];
2777 int within_build_tree = xstrcasecmp (p, "\\src") == 0;
2779 *p = 0;
2780 for (p = modname; *p; p = CharNext (p))
2781 if (*p == '\\') *p = '/';
2783 _snprintf (buf, sizeof (buf)-1, "emacs_dir=%s", modname);
2784 _putenv (strdup (buf));
2785 /* If we are running from the Posix-like build tree, define
2786 SHELL to point to our own cmdproxy. The loop below will
2787 then disregard PATH_EXEC and the default value. */
2788 if (within_build_tree)
2790 _snprintf (buf, sizeof (buf) - 1,
2791 "SHELL=%s/nt/cmdproxy.exe", modname);
2792 _putenv (strdup (buf));
2797 for (i = 0; i < N_ENV_VARS; i++)
2799 if (!getenv (env_vars[i].name))
2801 int dont_free = 0;
2802 char bufc[SET_ENV_BUF_SIZE];
2804 if ((lpval = w32_get_resource (env_vars[i].name, &dwType)) == NULL
2805 /* Also ignore empty environment variables. */
2806 || *lpval == 0)
2808 xfree (lpval);
2809 dont_free = 1;
2810 if (strcmp (env_vars[i].name, "SHELL") == 0)
2812 /* Look for cmdproxy.exe in every directory in
2813 PATH_EXEC. FIXME: This does not find cmdproxy
2814 in nt/ when we run uninstalled. */
2815 char fname[MAX_PATH];
2816 const char *pstart = PATH_EXEC, *pend;
2818 do {
2819 pend = _mbschr (pstart, ';');
2820 if (!pend)
2821 pend = pstart + strlen (pstart);
2822 /* Be defensive against series of ;;; characters. */
2823 if (pend > pstart)
2825 strncpy (fname, pstart, pend - pstart);
2826 fname[pend - pstart] = '/';
2827 strcpy (&fname[pend - pstart + 1], "cmdproxy.exe");
2828 ExpandEnvironmentStrings ((LPSTR) fname, bufc,
2829 sizeof (bufc));
2830 if (sys_access (bufc, F_OK) == 0)
2832 lpval = bufc;
2833 dwType = REG_SZ;
2834 break;
2837 if (*pend)
2838 pstart = pend + 1;
2839 else
2840 pstart = pend;
2841 if (!*pstart)
2843 /* If not found in any directory, use the
2844 default as the last resort. */
2845 lpval = (char *)env_vars[i].def_value;
2846 dwType = REG_EXPAND_SZ;
2848 } while (*pstart);
2850 else
2852 lpval = (char *)env_vars[i].def_value;
2853 dwType = REG_EXPAND_SZ;
2855 if (strcmp (env_vars[i].name, "HOME") == 0 && !appdata)
2856 Vdelayed_warnings_list
2857 = Fcons
2858 (listn (CONSTYPE_HEAP, 2,
2859 intern ("initialization"), build_string
2860 ("Use of `C:\\.emacs' without defining `HOME'\n"
2861 "in the environment is deprecated, "
2862 "see `Windows HOME' in the Emacs manual.")),
2863 Vdelayed_warnings_list);
2866 if (lpval)
2868 char buf1[SET_ENV_BUF_SIZE], buf2[SET_ENV_BUF_SIZE];
2870 if (dwType == REG_EXPAND_SZ)
2871 ExpandEnvironmentStrings ((LPSTR) lpval, buf1, sizeof (buf1));
2872 else if (dwType == REG_SZ)
2873 strcpy (buf1, (char *)lpval);
2874 if (dwType == REG_EXPAND_SZ || dwType == REG_SZ)
2876 _snprintf (buf2, sizeof (buf2)-1, "%s=%s", env_vars[i].name,
2877 buf1);
2878 _putenv (strdup (buf2));
2881 if (!dont_free)
2882 xfree (lpval);
2888 /* Rebuild system configuration to reflect invoking system. */
2889 Vsystem_configuration = build_string (EMACS_CONFIGURATION);
2891 /* Another special case: on NT, the PATH variable is actually named
2892 "Path" although cmd.exe (perhaps NT itself) arranges for
2893 environment variable lookup and setting to be case insensitive.
2894 However, Emacs assumes a fully case sensitive environment, so we
2895 need to change "Path" to "PATH" to match the expectations of
2896 various elisp packages. We do this by the sneaky method of
2897 modifying the string in the C runtime environ entry.
2899 The same applies to COMSPEC. */
2901 char ** envp;
2902 const char *path = "PATH=";
2903 int path_len = strlen (path);
2904 const char *comspec = "COMSPEC=";
2905 int comspec_len = strlen (comspec);
2907 for (envp = environ; *envp; envp++)
2908 if (_strnicmp (*envp, path, path_len) == 0)
2909 memcpy (*envp, path, path_len);
2910 else if (_strnicmp (*envp, comspec, comspec_len) == 0)
2911 memcpy (*envp, comspec, comspec_len);
2913 /* Make the same modification to `process-environment' which has
2914 already been initialized in set_initial_environment. */
2915 for (Lisp_Object env = Vprocess_environment; CONSP (env); env = XCDR (env))
2917 Lisp_Object entry = XCAR (env);
2918 if (_strnicmp (SDATA (entry), path, path_len) == 0)
2919 for (int i = 0; i < path_len; i++)
2920 SSET (entry, i, path[i]);
2921 else if (_strnicmp (SDATA (entry), comspec, comspec_len) == 0)
2922 for (int i = 0; i < comspec_len; i++)
2923 SSET (entry, i, comspec[i]);
2927 /* Remember the initial working directory for getcwd. */
2928 /* FIXME: Do we need to resolve possible symlinks in startup_dir?
2929 Does it matter anywhere in Emacs? */
2930 if (w32_unicode_filenames)
2932 wchar_t wstartup_dir[MAX_PATH];
2934 if (!GetCurrentDirectoryW (MAX_PATH, wstartup_dir))
2935 emacs_abort ();
2936 filename_from_utf16 (wstartup_dir, startup_dir);
2938 else
2940 char astartup_dir[MAX_PATH];
2942 if (!GetCurrentDirectoryA (MAX_PATH, astartup_dir))
2943 emacs_abort ();
2944 filename_from_ansi (astartup_dir, startup_dir);
2948 static char modname[MAX_PATH];
2950 if (!GetModuleFileNameA (NULL, modname, MAX_PATH))
2951 emacs_abort ();
2952 argv[0] = modname;
2955 /* Determine if there is a middle mouse button, to allow parse_button
2956 to decide whether right mouse events should be mouse-2 or
2957 mouse-3. */
2958 w32_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);
2960 init_user_info ();
2963 /* Called from expand-file-name when default-directory is not a string. */
2965 char *
2966 emacs_root_dir (void)
2968 static char root_dir[MAX_UTF8_PATH];
2969 const char *p;
2971 p = getenv ("emacs_dir");
2972 if (p == NULL)
2973 emacs_abort ();
2974 filename_from_ansi (p, root_dir);
2975 root_dir[parse_root (root_dir, NULL)] = '\0';
2976 dostounix_filename (root_dir);
2977 return root_dir;
2980 /* Emulate fdutimens. */
2982 /* Set the access and modification time stamps of FD (a.k.a. FILE) to be
2983 TIMESPEC[0] and TIMESPEC[1], respectively.
2984 FD must be either negative -- in which case it is ignored --
2985 or a file descriptor that is open on FILE.
2986 If FD is nonnegative, then FILE can be NULL, which means
2987 use just futimes instead of utimes.
2988 If TIMESPEC is null, FAIL.
2989 Return 0 on success, -1 (setting errno) on failure. */
2992 fdutimens (int fd, char const *file, struct timespec const timespec[2])
2994 if (!timespec)
2996 errno = ENOSYS;
2997 return -1;
2999 if (fd < 0 && !file)
3001 errno = EBADF;
3002 return -1;
3004 /* _futime's prototype defines 2nd arg as having the type 'struct
3005 _utimbuf', while utime needs to accept 'struct utimbuf' for
3006 compatibility with Posix. So we need to use 2 different (but
3007 equivalent) types to avoid compiler warnings, sigh. */
3008 if (fd >= 0)
3010 struct _utimbuf _ut;
3012 _ut.actime = timespec[0].tv_sec;
3013 _ut.modtime = timespec[1].tv_sec;
3014 return _futime (fd, &_ut);
3016 else
3018 struct utimbuf ut;
3020 ut.actime = timespec[0].tv_sec;
3021 ut.modtime = timespec[1].tv_sec;
3022 /* Call 'utime', which is implemented below, not the MS library
3023 function, which fails on directories. */
3024 return utime (file, &ut);
3029 /* ------------------------------------------------------------------------- */
3030 /* IO support and wrapper functions for the Windows API. */
3031 /* ------------------------------------------------------------------------- */
3033 /* Place a wrapper around the MSVC version of ctime. It returns NULL
3034 on network directories, so we handle that case here.
3035 (Ulrich Leodolter, 1/11/95). */
3036 char *
3037 sys_ctime (const time_t *t)
3039 char *str = (char *) ctime (t);
3040 return (str ? str : (char *)"Sun Jan 01 00:00:00 1970");
3043 /* Emulate sleep...we could have done this with a define, but that
3044 would necessitate including windows.h in the files that used it.
3045 This is much easier. */
3046 void
3047 sys_sleep (int seconds)
3049 Sleep (seconds * 1000);
3052 /* Internal MSVC functions for low-level descriptor munging */
3053 extern int __cdecl _set_osfhnd (int fd, long h);
3054 extern int __cdecl _free_osfhnd (int fd);
3056 /* parallel array of private info on file handles */
3057 filedesc fd_info [ MAXDESC ];
3059 typedef struct volume_info_data {
3060 struct volume_info_data * next;
3062 /* time when info was obtained */
3063 DWORD timestamp;
3065 /* actual volume info */
3066 char * root_dir;
3067 DWORD serialnum;
3068 DWORD maxcomp;
3069 DWORD flags;
3070 char * name;
3071 char * type;
3072 } volume_info_data;
3074 /* Global referenced by various functions. */
3075 static volume_info_data volume_info;
3077 /* Vector to indicate which drives are local and fixed (for which cached
3078 data never expires). */
3079 static BOOL fixed_drives[26];
3081 /* Consider cached volume information to be stale if older than 10s,
3082 at least for non-local drives. Info for fixed drives is never stale. */
3083 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
3084 #define VOLINFO_STILL_VALID( root_dir, info ) \
3085 ( ( isalpha (root_dir[0]) && \
3086 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
3087 || GetTickCount () - info->timestamp < 10000 )
3089 /* Cache support functions. */
3091 /* Simple linked list with linear search is sufficient. */
3092 static volume_info_data *volume_cache = NULL;
3094 static volume_info_data *
3095 lookup_volume_info (char * root_dir)
3097 volume_info_data * info;
3099 for (info = volume_cache; info; info = info->next)
3100 if (xstrcasecmp (info->root_dir, root_dir) == 0)
3101 break;
3102 return info;
3105 static void
3106 add_volume_info (char * root_dir, volume_info_data * info)
3108 info->root_dir = xstrdup (root_dir);
3109 unixtodos_filename (info->root_dir);
3110 info->next = volume_cache;
3111 volume_cache = info;
3115 /* Wrapper for GetVolumeInformation, which uses caching to avoid
3116 performance penalty (~2ms on 486 for local drives, 7.5ms for local
3117 cdrom drive, ~5-10ms or more for remote drives on LAN). */
3118 static volume_info_data *
3119 GetCachedVolumeInformation (char * root_dir)
3121 volume_info_data * info;
3122 char default_root[ MAX_UTF8_PATH ];
3123 char name[MAX_PATH+1];
3124 char type[MAX_PATH+1];
3126 /* NULL for root_dir means use root from current directory. */
3127 if (root_dir == NULL)
3129 if (w32_unicode_filenames)
3131 wchar_t curdirw[MAX_PATH];
3133 if (GetCurrentDirectoryW (MAX_PATH, curdirw) == 0)
3134 return NULL;
3135 filename_from_utf16 (curdirw, default_root);
3137 else
3139 char curdira[MAX_PATH];
3141 if (GetCurrentDirectoryA (MAX_PATH, curdira) == 0)
3142 return NULL;
3143 filename_from_ansi (curdira, default_root);
3145 parse_root (default_root, (const char **)&root_dir);
3146 *root_dir = 0;
3147 root_dir = default_root;
3150 /* Local fixed drives can be cached permanently. Removable drives
3151 cannot be cached permanently, since the volume name and serial
3152 number (if nothing else) can change. Remote drives should be
3153 treated as if they are removable, since there is no sure way to
3154 tell whether they are or not. Also, the UNC association of drive
3155 letters mapped to remote volumes can be changed at any time (even
3156 by other processes) without notice.
3158 As a compromise, so we can benefit from caching info for remote
3159 volumes, we use a simple expiry mechanism to invalidate cache
3160 entries that are more than ten seconds old. */
3162 #if 0
3163 /* No point doing this, because WNetGetConnection is even slower than
3164 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
3165 GetDriveType is about the only call of this type which does not
3166 involve network access, and so is extremely quick). */
3168 /* Map drive letter to UNC if remote. */
3169 if (isalpha (root_dir[0]) && !fixed[DRIVE_INDEX (root_dir[0])])
3171 char remote_name[ 256 ];
3172 char drive[3] = { root_dir[0], ':' };
3174 if (WNetGetConnection (drive, remote_name, sizeof (remote_name))
3175 == NO_ERROR)
3176 /* do something */ ;
3178 #endif
3180 info = lookup_volume_info (root_dir);
3182 if (info == NULL || ! VOLINFO_STILL_VALID (root_dir, info))
3184 DWORD serialnum;
3185 DWORD maxcomp;
3186 DWORD flags;
3188 /* Info is not cached, or is stale. */
3189 if (w32_unicode_filenames)
3191 wchar_t root_w[MAX_PATH];
3192 wchar_t name_w[MAX_PATH+1];
3193 wchar_t type_w[MAX_PATH+1];
3195 filename_to_utf16 (root_dir, root_w);
3196 if (!GetVolumeInformationW (root_w,
3197 name_w, sizeof (name_w),
3198 &serialnum,
3199 &maxcomp,
3200 &flags,
3201 type_w, sizeof (type_w)))
3202 return NULL;
3203 /* Hmm... not really 100% correct, as these 2 are not file
3204 names... */
3205 filename_from_utf16 (name_w, name);
3206 filename_from_utf16 (type_w, type);
3208 else
3210 char root_a[MAX_PATH];
3211 char name_a[MAX_PATH+1];
3212 char type_a[MAX_PATH+1];
3214 filename_to_ansi (root_dir, root_a);
3215 if (!GetVolumeInformationA (root_a,
3216 name_a, sizeof (name_a),
3217 &serialnum,
3218 &maxcomp,
3219 &flags,
3220 type_a, sizeof (type_a)))
3221 return NULL;
3222 filename_from_ansi (name_a, name);
3223 filename_from_ansi (type_a, type);
3226 /* Cache the volume information for future use, overwriting existing
3227 entry if present. */
3228 if (info == NULL)
3230 info = xmalloc (sizeof (volume_info_data));
3231 add_volume_info (root_dir, info);
3233 else
3235 xfree (info->name);
3236 xfree (info->type);
3239 info->name = xstrdup (name);
3240 unixtodos_filename (info->name);
3241 info->serialnum = serialnum;
3242 info->maxcomp = maxcomp;
3243 info->flags = flags;
3244 info->type = xstrdup (type);
3245 info->timestamp = GetTickCount ();
3248 return info;
3251 /* Get information on the volume where NAME is held; set path pointer to
3252 start of pathname in NAME (past UNC header\volume header if present),
3253 if pPath is non-NULL.
3255 Note: if NAME includes symlinks, the information is for the volume
3256 of the symlink, not of its target. That's because, even though
3257 GetVolumeInformation returns information about the symlink target
3258 of its argument, we only pass the root directory to
3259 GetVolumeInformation, not the full NAME. */
3260 static int
3261 get_volume_info (const char * name, const char ** pPath)
3263 char temp[MAX_UTF8_PATH];
3264 char *rootname = NULL; /* default to current volume */
3265 volume_info_data * info;
3266 int root_len = parse_root (name, pPath);
3268 if (name == NULL)
3269 return FALSE;
3271 /* Copy the root name of the volume, if given. */
3272 if (root_len)
3274 strncpy (temp, name, root_len);
3275 temp[root_len] = '\0';
3276 unixtodos_filename (temp);
3277 rootname = temp;
3280 info = GetCachedVolumeInformation (rootname);
3281 if (info != NULL)
3283 /* Set global referenced by other functions. */
3284 volume_info = *info;
3285 return TRUE;
3287 return FALSE;
3290 /* Determine if volume is FAT format (ie. only supports short 8.3
3291 names); also set path pointer to start of pathname in name, if
3292 pPath is non-NULL. */
3293 static int
3294 is_fat_volume (const char * name, const char ** pPath)
3296 if (get_volume_info (name, pPath))
3297 return (volume_info.maxcomp == 12);
3298 return FALSE;
3301 /* Convert all slashes in a filename to backslashes, and map filename
3302 to a valid 8.3 name if necessary. The result is a pointer to a
3303 static buffer, so CAVEAT EMPTOR! */
3304 const char *map_w32_filename (const char *, const char **);
3306 const char *
3307 map_w32_filename (const char * name, const char ** pPath)
3309 static char shortname[MAX_UTF8_PATH];
3310 char * str = shortname;
3311 char c;
3312 char * path;
3313 const char * save_name = name;
3315 if (strlen (name) >= sizeof (shortname))
3317 /* Return a filename which will cause callers to fail. */
3318 strcpy (shortname, "?");
3319 return shortname;
3322 if (!fatal_error_in_progress /* disable fancy processing during crash */
3323 && is_fat_volume (name, (const char **)&path)) /* truncate to 8.3 */
3325 register int left = 8; /* maximum number of chars in part */
3326 register int extn = 0; /* extension added? */
3327 register int dots = 2; /* maximum number of dots allowed */
3329 while (name < path)
3330 *str++ = *name++; /* skip past UNC header */
3332 while ((c = *name++))
3334 switch ( c )
3336 case ':':
3337 case '\\':
3338 case '/':
3339 *str++ = (c == ':' ? ':' : '\\');
3340 extn = 0; /* reset extension flags */
3341 dots = 2; /* max 2 dots */
3342 left = 8; /* max length 8 for main part */
3343 break;
3344 case '.':
3345 if ( dots )
3347 /* Convert path components of the form .xxx to _xxx,
3348 but leave . and .. as they are. This allows .emacs
3349 to be read as _emacs, for example. */
3351 if (! *name ||
3352 *name == '.' ||
3353 IS_DIRECTORY_SEP (*name))
3355 *str++ = '.';
3356 dots--;
3358 else
3360 *str++ = '_';
3361 left--;
3362 dots = 0;
3365 else if ( !extn )
3367 *str++ = '.';
3368 extn = 1; /* we've got an extension */
3369 left = 3; /* 3 chars in extension */
3371 else
3373 /* any embedded dots after the first are converted to _ */
3374 *str++ = '_';
3376 break;
3377 case '~':
3378 case '#': /* don't lose these, they're important */
3379 if ( ! left )
3380 str[-1] = c; /* replace last character of part */
3381 /* FALLTHRU */
3382 default:
3383 if ( left && 'A' <= c && c <= 'Z' )
3385 *str++ = tolower (c); /* map to lower case (looks nicer) */
3386 left--;
3387 dots = 0; /* started a path component */
3389 break;
3392 *str = '\0';
3394 else
3396 strcpy (shortname, name);
3397 unixtodos_filename (shortname);
3400 if (pPath)
3401 *pPath = shortname + (path - save_name);
3403 return shortname;
3406 static int
3407 is_exec (const char * name)
3409 char * p = strrchr (name, '.');
3410 return
3411 (p != NULL
3412 && (xstrcasecmp (p, ".exe") == 0 ||
3413 xstrcasecmp (p, ".com") == 0 ||
3414 xstrcasecmp (p, ".bat") == 0 ||
3415 xstrcasecmp (p, ".cmd") == 0));
3418 /* Emulate the Unix directory procedures opendir, closedir, and
3419 readdir. We rename them to sys_* names because some versions of
3420 MinGW startup code call opendir and readdir to glob wildcards, and
3421 the code that calls them doesn't grok UTF-8 encoded file names we
3422 produce in dirent->d_name[]. */
3424 struct dirent dir_static; /* simulated directory contents */
3425 static HANDLE dir_find_handle = INVALID_HANDLE_VALUE;
3426 static int dir_is_fat;
3427 static char dir_pathname[MAX_UTF8_PATH];
3428 static WIN32_FIND_DATAW dir_find_data_w;
3429 static WIN32_FIND_DATAA dir_find_data_a;
3430 #define DIR_FIND_DATA_W 1
3431 #define DIR_FIND_DATA_A 2
3432 static int last_dir_find_data = -1;
3434 /* Support shares on a network resource as subdirectories of a read-only
3435 root directory. */
3436 static HANDLE wnet_enum_handle = INVALID_HANDLE_VALUE;
3437 static HANDLE open_unc_volume (const char *);
3438 static void *read_unc_volume (HANDLE, wchar_t *, char *, int);
3439 static void close_unc_volume (HANDLE);
3441 DIR *
3442 sys_opendir (const char *filename)
3444 DIR *dirp;
3446 /* Opening is done by FindFirstFile. However, a read is inherent to
3447 this operation, so we defer the open until read time. */
3449 if (dir_find_handle != INVALID_HANDLE_VALUE)
3450 return NULL;
3451 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
3452 return NULL;
3454 /* Note: We don't support traversal of UNC volumes via symlinks.
3455 Doing so would mean punishing 99.99% of use cases by resolving
3456 all the possible symlinks in FILENAME, recursively. */
3457 if (is_unc_volume (filename))
3459 wnet_enum_handle = open_unc_volume (filename);
3460 if (wnet_enum_handle == INVALID_HANDLE_VALUE)
3461 return NULL;
3464 if (!(dirp = (DIR *) malloc (sizeof (DIR))))
3465 return NULL;
3467 dirp->dd_fd = 0;
3468 dirp->dd_loc = 0;
3469 dirp->dd_size = 0;
3471 strncpy (dir_pathname, map_w32_filename (filename, NULL), MAX_UTF8_PATH - 1);
3472 dir_pathname[MAX_UTF8_PATH - 1] = '\0';
3473 /* Note: We don't support symlinks to file names on FAT volumes.
3474 Doing so would mean punishing 99.99% of use cases by resolving
3475 all the possible symlinks in FILENAME, recursively. */
3476 dir_is_fat = is_fat_volume (filename, NULL);
3478 return dirp;
3481 void
3482 sys_closedir (DIR *dirp)
3484 /* If we have a find-handle open, close it. */
3485 if (dir_find_handle != INVALID_HANDLE_VALUE)
3487 FindClose (dir_find_handle);
3488 dir_find_handle = INVALID_HANDLE_VALUE;
3490 else if (wnet_enum_handle != INVALID_HANDLE_VALUE)
3492 close_unc_volume (wnet_enum_handle);
3493 wnet_enum_handle = INVALID_HANDLE_VALUE;
3495 xfree ((char *) dirp);
3498 struct dirent *
3499 sys_readdir (DIR *dirp)
3501 int downcase = !NILP (Vw32_downcase_file_names);
3503 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
3505 if (!read_unc_volume (wnet_enum_handle,
3506 dir_find_data_w.cFileName,
3507 dir_find_data_a.cFileName,
3508 MAX_PATH))
3509 return NULL;
3511 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
3512 else if (dir_find_handle == INVALID_HANDLE_VALUE)
3514 char filename[MAX_UTF8_PATH];
3515 int ln;
3516 bool last_slash = true;
3518 /* Note: We don't need to worry about dir_pathname being longer
3519 than MAX_UTF8_PATH, as sys_opendir already took care of that
3520 when it called map_w32_filename: that function will put a "?"
3521 in its return value in that case, thus failing all the calls
3522 below. */
3523 strcpy (filename, dir_pathname);
3524 ln = strlen (filename);
3525 if (!IS_DIRECTORY_SEP (filename[ln - 1]))
3526 last_slash = false;
3528 /* Note: No need to resolve symlinks in FILENAME, because
3529 FindFirst opens the directory that is the target of a
3530 symlink. */
3531 if (w32_unicode_filenames)
3533 wchar_t fnw[MAX_PATH + 2];
3535 filename_to_utf16 (filename, fnw);
3536 if (!last_slash)
3537 wcscat (fnw, L"\\");
3538 wcscat (fnw, L"*");
3539 dir_find_handle = FindFirstFileW (fnw, &dir_find_data_w);
3541 else
3543 char fna[MAX_PATH + 2];
3545 filename_to_ansi (filename, fna);
3546 if (!last_slash)
3547 strcat (fna, "\\");
3548 strcat (fna, "*");
3549 /* If FILENAME is not representable by the current ANSI
3550 codepage, we don't want FindFirstFileA to interpret the
3551 '?' characters as a wildcard. */
3552 if (_mbspbrk (fna, "?"))
3553 dir_find_handle = INVALID_HANDLE_VALUE;
3554 else
3555 dir_find_handle = FindFirstFileA (fna, &dir_find_data_a);
3558 if (dir_find_handle == INVALID_HANDLE_VALUE)
3560 /* Any changes in the value of errno here should be in sync
3561 with what directory_files_internal does when it calls
3562 readdir. */
3563 switch (GetLastError ())
3565 /* Windows uses this value when FindFirstFile finds no
3566 files that match the wildcard. This is not supposed
3567 to happen, since our wildcard is "*", but just in
3568 case, if there's some weird empty directory with not
3569 even "." and ".." entries... */
3570 case ERROR_FILE_NOT_FOUND:
3571 errno = 0;
3572 /* FALLTHRU */
3573 default:
3574 break;
3575 case ERROR_ACCESS_DENIED:
3576 case ERROR_NETWORK_ACCESS_DENIED:
3577 errno = EACCES;
3578 break;
3579 case ERROR_PATH_NOT_FOUND:
3580 case ERROR_INVALID_DRIVE:
3581 case ERROR_NOT_READY:
3582 case ERROR_BAD_NETPATH:
3583 case ERROR_BAD_NET_NAME:
3584 errno = ENOENT;
3585 break;
3587 return NULL;
3590 else if (w32_unicode_filenames)
3592 if (!FindNextFileW (dir_find_handle, &dir_find_data_w))
3594 errno = 0;
3595 return NULL;
3598 else
3600 if (!FindNextFileA (dir_find_handle, &dir_find_data_a))
3602 errno = 0;
3603 return NULL;
3607 /* Emacs never uses this value, so don't bother making it match
3608 value returned by stat(). */
3609 dir_static.d_ino = 1;
3611 if (w32_unicode_filenames)
3613 if (downcase || dir_is_fat)
3615 wchar_t tem[MAX_PATH];
3617 wcscpy (tem, dir_find_data_w.cFileName);
3618 CharLowerW (tem);
3619 filename_from_utf16 (tem, dir_static.d_name);
3621 else
3622 filename_from_utf16 (dir_find_data_w.cFileName, dir_static.d_name);
3623 last_dir_find_data = DIR_FIND_DATA_W;
3625 else
3627 char tem[MAX_PATH];
3629 /* If the file name in cFileName[] includes `?' characters, it
3630 means the original file name used characters that cannot be
3631 represented by the current ANSI codepage. To avoid total
3632 lossage, retrieve the short 8+3 alias of the long file
3633 name. */
3634 if (_mbspbrk (dir_find_data_a.cFileName, "?"))
3636 strcpy (tem, dir_find_data_a.cAlternateFileName);
3637 /* 8+3 aliases are returned in all caps, which could break
3638 various alists that look at filenames' extensions. */
3639 downcase = 1;
3641 else if (downcase || dir_is_fat)
3642 strcpy (tem, dir_find_data_a.cFileName);
3643 else
3644 filename_from_ansi (dir_find_data_a.cFileName, dir_static.d_name);
3645 if (downcase || dir_is_fat)
3647 _mbslwr (tem);
3648 filename_from_ansi (tem, dir_static.d_name);
3650 last_dir_find_data = DIR_FIND_DATA_A;
3653 dir_static.d_namlen = strlen (dir_static.d_name);
3654 dir_static.d_reclen = sizeof (struct dirent) - MAX_UTF8_PATH + 3 +
3655 dir_static.d_namlen - dir_static.d_namlen % 4;
3657 return &dir_static;
3660 static HANDLE
3661 open_unc_volume (const char *path)
3663 const char *fn = map_w32_filename (path, NULL);
3664 DWORD result;
3665 HANDLE henum;
3667 if (w32_unicode_filenames)
3669 NETRESOURCEW nrw;
3670 wchar_t fnw[MAX_PATH];
3672 nrw.dwScope = RESOURCE_GLOBALNET;
3673 nrw.dwType = RESOURCETYPE_DISK;
3674 nrw.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
3675 nrw.dwUsage = RESOURCEUSAGE_CONTAINER;
3676 nrw.lpLocalName = NULL;
3677 filename_to_utf16 (fn, fnw);
3678 nrw.lpRemoteName = fnw;
3679 nrw.lpComment = NULL;
3680 nrw.lpProvider = NULL;
3682 result = WNetOpenEnumW (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
3683 RESOURCEUSAGE_CONNECTABLE, &nrw, &henum);
3685 else
3687 NETRESOURCEA nra;
3688 char fna[MAX_PATH];
3690 nra.dwScope = RESOURCE_GLOBALNET;
3691 nra.dwType = RESOURCETYPE_DISK;
3692 nra.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
3693 nra.dwUsage = RESOURCEUSAGE_CONTAINER;
3694 nra.lpLocalName = NULL;
3695 filename_to_ansi (fn, fna);
3696 nra.lpRemoteName = fna;
3697 nra.lpComment = NULL;
3698 nra.lpProvider = NULL;
3700 result = WNetOpenEnumA (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
3701 RESOURCEUSAGE_CONNECTABLE, &nra, &henum);
3703 if (result == NO_ERROR)
3704 return henum;
3705 else
3707 /* Make sure directory_files_internal reports a sensible error. */
3708 errno = ENOENT;
3709 return INVALID_HANDLE_VALUE;
3713 static void *
3714 read_unc_volume (HANDLE henum, wchar_t *fname_w, char *fname_a, int size)
3716 DWORD count;
3717 int result;
3718 char *buffer;
3719 DWORD bufsize = 512;
3720 void *retval;
3722 count = 1;
3723 if (w32_unicode_filenames)
3725 wchar_t *ptrw;
3727 bufsize *= 2;
3728 buffer = alloca (bufsize);
3729 result = WNetEnumResourceW (henum, &count, buffer, &bufsize);
3730 if (result != NO_ERROR)
3731 return NULL;
3732 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
3733 ptrw = ((LPNETRESOURCEW) buffer)->lpRemoteName;
3734 ptrw += 2;
3735 while (*ptrw && *ptrw != L'/' && *ptrw != L'\\') ptrw++;
3736 ptrw++;
3737 wcsncpy (fname_w, ptrw, size);
3738 retval = fname_w;
3740 else
3742 int dbcs_p = max_filename_mbslen () > 1;
3743 char *ptra;
3745 buffer = alloca (bufsize);
3746 result = WNetEnumResourceA (henum, &count, buffer, &bufsize);
3747 if (result != NO_ERROR)
3748 return NULL;
3749 ptra = ((LPNETRESOURCEA) buffer)->lpRemoteName;
3750 ptra += 2;
3751 if (!dbcs_p)
3752 while (*ptra && !IS_DIRECTORY_SEP (*ptra)) ptra++;
3753 else
3755 while (*ptra && !IS_DIRECTORY_SEP (*ptra))
3756 ptra = CharNextExA (file_name_codepage, ptra, 0);
3758 ptra++;
3759 strncpy (fname_a, ptra, size);
3760 retval = fname_a;
3763 return retval;
3766 static void
3767 close_unc_volume (HANDLE henum)
3769 if (henum != INVALID_HANDLE_VALUE)
3770 WNetCloseEnum (henum);
3773 static DWORD
3774 unc_volume_file_attributes (const char *path)
3776 HANDLE henum;
3777 DWORD attrs;
3779 henum = open_unc_volume (path);
3780 if (henum == INVALID_HANDLE_VALUE)
3781 return -1;
3783 attrs = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY;
3785 close_unc_volume (henum);
3787 return attrs;
3790 /* Ensure a network connection is authenticated. */
3791 static void
3792 logon_network_drive (const char *path)
3794 char share[MAX_UTF8_PATH];
3795 int n_slashes;
3796 char drive[4];
3797 UINT drvtype;
3798 char *p;
3799 DWORD val;
3801 if (IS_DIRECTORY_SEP (path[0]) && IS_DIRECTORY_SEP (path[1]))
3802 drvtype = DRIVE_REMOTE;
3803 else if (path[0] == '\0' || path[1] != ':')
3804 drvtype = GetDriveType (NULL);
3805 else
3807 drive[0] = path[0];
3808 drive[1] = ':';
3809 drive[2] = '\\';
3810 drive[3] = '\0';
3811 drvtype = GetDriveType (drive);
3814 /* Only logon to networked drives. */
3815 if (drvtype != DRIVE_REMOTE)
3816 return;
3818 n_slashes = 2;
3819 strncpy (share, path, MAX_UTF8_PATH);
3820 /* Truncate to just server and share name. */
3821 for (p = share + 2; *p && p < share + MAX_UTF8_PATH; p++)
3823 if (IS_DIRECTORY_SEP (*p) && ++n_slashes > 3)
3825 *p = '\0';
3826 break;
3830 if (w32_unicode_filenames)
3832 NETRESOURCEW resourcew;
3833 wchar_t share_w[MAX_PATH];
3835 resourcew.dwScope = RESOURCE_GLOBALNET;
3836 resourcew.dwType = RESOURCETYPE_DISK;
3837 resourcew.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
3838 resourcew.dwUsage = RESOURCEUSAGE_CONTAINER;
3839 resourcew.lpLocalName = NULL;
3840 filename_to_utf16 (share, share_w);
3841 resourcew.lpRemoteName = share_w;
3842 resourcew.lpProvider = NULL;
3844 val = WNetAddConnection2W (&resourcew, NULL, NULL, CONNECT_INTERACTIVE);
3846 else
3848 NETRESOURCEA resourcea;
3849 char share_a[MAX_PATH];
3851 resourcea.dwScope = RESOURCE_GLOBALNET;
3852 resourcea.dwType = RESOURCETYPE_DISK;
3853 resourcea.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
3854 resourcea.dwUsage = RESOURCEUSAGE_CONTAINER;
3855 resourcea.lpLocalName = NULL;
3856 filename_to_ansi (share, share_a);
3857 resourcea.lpRemoteName = share_a;
3858 resourcea.lpProvider = NULL;
3860 val = WNetAddConnection2A (&resourcea, NULL, NULL, CONNECT_INTERACTIVE);
3863 switch (val)
3865 case NO_ERROR:
3866 case ERROR_ALREADY_ASSIGNED:
3867 break;
3868 case ERROR_ACCESS_DENIED:
3869 case ERROR_LOGON_FAILURE:
3870 errno = EACCES;
3871 break;
3872 case ERROR_BUSY:
3873 errno = EAGAIN;
3874 break;
3875 case ERROR_BAD_NET_NAME:
3876 case ERROR_NO_NET_OR_BAD_PATH:
3877 case ERROR_NO_NETWORK:
3878 case ERROR_CANCELLED:
3879 default:
3880 errno = ENOENT;
3881 break;
3885 /* Emulate faccessat(2). */
3887 faccessat (int dirfd, const char * path, int mode, int flags)
3889 DWORD attributes;
3890 char fullname[MAX_UTF8_PATH];
3892 /* Rely on a hack: an open directory is modeled as file descriptor 0,
3893 and its actual file name is stored in dir_pathname by opendir.
3894 This is good enough for the current usage in Emacs, but is fragile. */
3895 if (dirfd != AT_FDCWD
3896 && !(IS_DIRECTORY_SEP (path[0])
3897 || IS_DEVICE_SEP (path[1])))
3899 char lastc = dir_pathname[strlen (dir_pathname) - 1];
3901 if (_snprintf (fullname, sizeof fullname, "%s%s%s",
3902 dir_pathname, IS_DIRECTORY_SEP (lastc) ? "" : "/", path)
3903 < 0)
3905 errno = ENAMETOOLONG;
3906 return -1;
3908 path = fullname;
3911 if (IS_DIRECTORY_SEP (path[strlen (path) - 1]) && (mode & F_OK) != 0)
3912 mode |= D_OK;
3914 /* MSVCRT implementation of 'access' doesn't recognize D_OK, and its
3915 newer versions blow up when passed D_OK. */
3916 path = map_w32_filename (path, NULL);
3917 /* If the last element of PATH is a symlink, we need to resolve it
3918 to get the attributes of its target file. Note: any symlinks in
3919 PATH elements other than the last one are transparently resolved
3920 by GetFileAttributes below. */
3921 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0
3922 && (flags & AT_SYMLINK_NOFOLLOW) == 0)
3923 path = chase_symlinks (path);
3925 if (w32_unicode_filenames)
3927 wchar_t path_w[MAX_PATH];
3929 filename_to_utf16 (path, path_w);
3930 attributes = GetFileAttributesW (path_w);
3932 else
3934 char path_a[MAX_PATH];
3936 filename_to_ansi (path, path_a);
3937 attributes = GetFileAttributesA (path_a);
3940 if (attributes == -1)
3942 DWORD w32err = GetLastError ();
3944 switch (w32err)
3946 case ERROR_INVALID_NAME:
3947 case ERROR_BAD_PATHNAME:
3948 if (is_unc_volume (path))
3950 attributes = unc_volume_file_attributes (path);
3951 if (attributes == -1)
3953 errno = EACCES;
3954 return -1;
3956 goto check_attrs;
3958 /* FALLTHROUGH */
3959 case ERROR_FILE_NOT_FOUND:
3960 case ERROR_BAD_NETPATH:
3961 errno = ENOENT;
3962 break;
3963 default:
3964 errno = EACCES;
3965 break;
3967 return -1;
3970 check_attrs:
3971 if ((mode & X_OK) != 0
3972 && !(is_exec (path) || (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0))
3974 errno = EACCES;
3975 return -1;
3977 if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0)
3979 errno = EACCES;
3980 return -1;
3982 if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
3984 errno = EACCES;
3985 return -1;
3987 return 0;
3990 /* A special test for DIRNAME being a directory accessible by the
3991 current user. This is needed because the security permissions in
3992 directory's ACLs are not visible in the Posix-style mode bits
3993 returned by 'stat' and in attributes returned by GetFileAttributes.
3994 So a directory would seem like it's readable by the current user,
3995 but will in fact error out with EACCES when they actually try. */
3997 w32_accessible_directory_p (const char *dirname, ptrdiff_t dirlen)
3999 char pattern[MAX_UTF8_PATH];
4000 bool last_slash = dirlen > 0 && IS_DIRECTORY_SEP (dirname[dirlen - 1]);
4001 HANDLE dh;
4003 /* Network volumes need a different reading method. */
4004 if (is_unc_volume (dirname))
4006 void *read_result = NULL;
4007 wchar_t fnw[MAX_PATH];
4008 char fna[MAX_PATH];
4010 dh = open_unc_volume (dirname);
4011 if (dh != INVALID_HANDLE_VALUE)
4013 read_result = read_unc_volume (dh, fnw, fna, MAX_PATH);
4014 close_unc_volume (dh);
4016 /* Treat empty volumes as accessible. */
4017 return read_result != NULL || GetLastError () == ERROR_NO_MORE_ITEMS;
4020 /* Note: map_w32_filename makes sure DIRNAME is not longer than
4021 MAX_UTF8_PATH. */
4022 strcpy (pattern, map_w32_filename (dirname, NULL));
4024 /* Note: No need to resolve symlinks in FILENAME, because FindFirst
4025 opens the directory that is the target of a symlink. */
4026 if (w32_unicode_filenames)
4028 wchar_t pat_w[MAX_PATH + 2];
4029 WIN32_FIND_DATAW dfd_w;
4031 filename_to_utf16 (pattern, pat_w);
4032 if (!last_slash)
4033 wcscat (pat_w, L"\\");
4034 wcscat (pat_w, L"*");
4035 dh = FindFirstFileW (pat_w, &dfd_w);
4037 else
4039 char pat_a[MAX_PATH + 2];
4040 WIN32_FIND_DATAA dfd_a;
4042 filename_to_ansi (pattern, pat_a);
4043 if (!last_slash)
4044 strcpy (pat_a, "\\");
4045 strcat (pat_a, "*");
4046 /* In case DIRNAME cannot be expressed in characters from the
4047 current ANSI codepage. */
4048 if (_mbspbrk (pat_a, "?"))
4049 dh = INVALID_HANDLE_VALUE;
4050 else
4051 dh = FindFirstFileA (pat_a, &dfd_a);
4054 if (dh == INVALID_HANDLE_VALUE)
4055 return 0;
4056 FindClose (dh);
4057 return 1;
4060 /* A version of 'access' to be used locally with file names in
4061 locale-specific encoding. Does not resolve symlinks and does not
4062 support file names on FAT12 and FAT16 volumes, but that's OK, since
4063 we only invoke this function for files inside the Emacs source or
4064 installation tree, on directories (so any symlinks should have the
4065 directory bit set), and on short file names such as "C:/.emacs". */
4066 static int
4067 sys_access (const char *fname, int mode)
4069 char fname_copy[MAX_PATH], *p;
4070 DWORD attributes;
4072 strcpy (fname_copy, fname);
4073 /* Do the equivalent of unixtodos_filename. */
4074 for (p = fname_copy; *p; p = CharNext (p))
4075 if (*p == '/')
4076 *p = '\\';
4078 if ((attributes = GetFileAttributesA (fname_copy)) == -1)
4080 DWORD w32err = GetLastError ();
4082 switch (w32err)
4084 case ERROR_INVALID_NAME:
4085 case ERROR_BAD_PATHNAME:
4086 case ERROR_FILE_NOT_FOUND:
4087 case ERROR_BAD_NETPATH:
4088 errno = ENOENT;
4089 break;
4090 default:
4091 errno = EACCES;
4092 break;
4094 return -1;
4096 if ((mode & X_OK) != 0
4097 && !(is_exec (fname_copy)
4098 || (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0))
4100 errno = EACCES;
4101 return -1;
4103 if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0)
4105 errno = EACCES;
4106 return -1;
4108 if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
4110 errno = EACCES;
4111 return -1;
4113 return 0;
4116 /* Shadow some MSVC runtime functions to map requests for long filenames
4117 to reasonable short names if necessary. This was originally added to
4118 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
4119 long file names. */
4122 sys_chdir (const char * path)
4124 path = map_w32_filename (path, NULL);
4125 if (w32_unicode_filenames)
4127 wchar_t newdir_w[MAX_PATH];
4129 if (filename_to_utf16 (path, newdir_w) == 0)
4130 return _wchdir (newdir_w);
4131 return -1;
4133 else
4135 char newdir_a[MAX_PATH];
4137 if (filename_to_ansi (path, newdir_a) == 0)
4138 return _chdir (newdir_a);
4139 return -1;
4144 sys_chmod (const char * path, int mode)
4146 path = chase_symlinks (map_w32_filename (path, NULL));
4147 if (w32_unicode_filenames)
4149 wchar_t path_w[MAX_PATH];
4151 filename_to_utf16 (path, path_w);
4152 return _wchmod (path_w, mode);
4154 else
4156 char path_a[MAX_PATH];
4158 filename_to_ansi (path, path_a);
4159 return _chmod (path_a, mode);
4164 sys_creat (const char * path, int mode)
4166 path = map_w32_filename (path, NULL);
4167 if (w32_unicode_filenames)
4169 wchar_t path_w[MAX_PATH];
4171 filename_to_utf16 (path, path_w);
4172 return _wcreat (path_w, mode);
4174 else
4176 char path_a[MAX_PATH];
4178 filename_to_ansi (path, path_a);
4179 return _creat (path_a, mode);
4183 FILE *
4184 sys_fopen (const char * path, const char * mode)
4186 int fd;
4187 int oflag;
4188 const char * mode_save = mode;
4190 /* Force all file handles to be non-inheritable. This is necessary to
4191 ensure child processes don't unwittingly inherit handles that might
4192 prevent future file access. */
4194 if (mode[0] == 'r')
4195 oflag = O_RDONLY;
4196 else if (mode[0] == 'w' || mode[0] == 'a')
4197 oflag = O_WRONLY | O_CREAT | O_TRUNC;
4198 else
4199 return NULL;
4201 /* Only do simplistic option parsing. */
4202 while (*++mode)
4203 if (mode[0] == '+')
4205 oflag &= ~(O_RDONLY | O_WRONLY);
4206 oflag |= O_RDWR;
4208 else if (mode[0] == 'b')
4210 oflag &= ~O_TEXT;
4211 oflag |= O_BINARY;
4213 else if (mode[0] == 't')
4215 oflag &= ~O_BINARY;
4216 oflag |= O_TEXT;
4218 else break;
4220 path = map_w32_filename (path, NULL);
4221 if (w32_unicode_filenames)
4223 wchar_t path_w[MAX_PATH];
4225 filename_to_utf16 (path, path_w);
4226 fd = _wopen (path_w, oflag | _O_NOINHERIT, 0644);
4228 else
4230 char path_a[MAX_PATH];
4232 filename_to_ansi (path, path_a);
4233 fd = _open (path_a, oflag | _O_NOINHERIT, 0644);
4235 if (fd < 0)
4236 return NULL;
4238 return _fdopen (fd, mode_save);
4241 /* This only works on NTFS volumes, but is useful to have. */
4243 sys_link (const char * old, const char * new)
4245 HANDLE fileh;
4246 int result = -1;
4247 char oldname[MAX_UTF8_PATH], newname[MAX_UTF8_PATH];
4248 wchar_t oldname_w[MAX_PATH];
4249 char oldname_a[MAX_PATH];
4251 if (old == NULL || new == NULL)
4253 errno = ENOENT;
4254 return -1;
4257 strcpy (oldname, map_w32_filename (old, NULL));
4258 strcpy (newname, map_w32_filename (new, NULL));
4260 if (w32_unicode_filenames)
4262 filename_to_utf16 (oldname, oldname_w);
4263 fileh = CreateFileW (oldname_w, 0, 0, NULL, OPEN_EXISTING,
4264 FILE_FLAG_BACKUP_SEMANTICS, NULL);
4266 else
4268 filename_to_ansi (oldname, oldname_a);
4269 fileh = CreateFileA (oldname_a, 0, 0, NULL, OPEN_EXISTING,
4270 FILE_FLAG_BACKUP_SEMANTICS, NULL);
4272 if (fileh != INVALID_HANDLE_VALUE)
4274 int wlen;
4276 /* Confusingly, the "alternate" stream name field does not apply
4277 when restoring a hard link, and instead contains the actual
4278 stream data for the link (ie. the name of the link to create).
4279 The WIN32_STREAM_ID structure before the cStreamName field is
4280 the stream header, which is then immediately followed by the
4281 stream data. */
4283 struct {
4284 WIN32_STREAM_ID wid;
4285 WCHAR wbuffer[MAX_PATH]; /* extra space for link name */
4286 } data;
4288 /* We used to pass MB_PRECOMPOSED as the 2nd arg here, but MSDN
4289 indicates that flag is unsupported for CP_UTF8, and OTOH says
4290 it is the default anyway. */
4291 wlen = pMultiByteToWideChar (CP_UTF8, 0, newname, -1,
4292 data.wid.cStreamName, MAX_PATH);
4293 if (wlen > 0)
4295 LPVOID context = NULL;
4296 DWORD wbytes = 0;
4298 data.wid.dwStreamId = BACKUP_LINK;
4299 data.wid.dwStreamAttributes = 0;
4300 data.wid.Size.LowPart = wlen * sizeof (WCHAR);
4301 data.wid.Size.HighPart = 0;
4302 data.wid.dwStreamNameSize = 0;
4304 if (BackupWrite (fileh, (LPBYTE)&data,
4305 offsetof (WIN32_STREAM_ID, cStreamName)
4306 + data.wid.Size.LowPart,
4307 &wbytes, FALSE, FALSE, &context)
4308 && BackupWrite (fileh, NULL, 0, &wbytes, TRUE, FALSE, &context))
4310 /* succeeded */
4311 result = 0;
4313 else
4315 DWORD err = GetLastError ();
4316 DWORD attributes;
4318 switch (err)
4320 case ERROR_ACCESS_DENIED:
4321 /* This is what happens when OLDNAME is a directory,
4322 since Windows doesn't support hard links to
4323 directories. Posix says to set errno to EPERM in
4324 that case. */
4325 if (w32_unicode_filenames)
4326 attributes = GetFileAttributesW (oldname_w);
4327 else
4328 attributes = GetFileAttributesA (oldname_a);
4329 if (attributes != -1
4330 && (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
4331 errno = EPERM;
4332 else if (attributes == -1
4333 && is_unc_volume (oldname)
4334 && unc_volume_file_attributes (oldname) != -1)
4335 errno = EPERM;
4336 else
4337 errno = EACCES;
4338 break;
4339 case ERROR_TOO_MANY_LINKS:
4340 errno = EMLINK;
4341 break;
4342 case ERROR_NOT_SAME_DEVICE:
4343 errno = EXDEV;
4344 break;
4345 default:
4346 errno = EINVAL;
4347 break;
4352 CloseHandle (fileh);
4354 else
4355 errno = ENOENT;
4357 return result;
4361 sys_mkdir (const char * path, mode_t mode)
4363 path = map_w32_filename (path, NULL);
4365 if (w32_unicode_filenames)
4367 wchar_t path_w[MAX_PATH];
4369 filename_to_utf16 (path, path_w);
4370 return _wmkdir (path_w);
4372 else
4374 char path_a[MAX_PATH];
4376 filename_to_ansi (path, path_a);
4377 return _mkdir (path_a);
4382 sys_open (const char * path, int oflag, int mode)
4384 const char* mpath = map_w32_filename (path, NULL);
4385 int res = -1;
4387 if (w32_unicode_filenames)
4389 wchar_t mpath_w[MAX_PATH];
4391 filename_to_utf16 (mpath, mpath_w);
4392 /* If possible, try to open file without _O_CREAT, to be able to
4393 write to existing hidden and system files. Force all file
4394 handles to be non-inheritable. */
4395 if ((oflag & (_O_CREAT | _O_EXCL)) != (_O_CREAT | _O_EXCL))
4396 res = _wopen (mpath_w, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
4397 if (res < 0)
4398 res = _wopen (mpath_w, oflag | _O_NOINHERIT, mode);
4400 else
4402 char mpath_a[MAX_PATH];
4404 filename_to_ansi (mpath, mpath_a);
4405 if ((oflag & (_O_CREAT | _O_EXCL)) != (_O_CREAT | _O_EXCL))
4406 res = _open (mpath_a, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
4407 if (res < 0)
4408 res = _open (mpath_a, oflag | _O_NOINHERIT, mode);
4411 return res;
4415 fchmod (int fd, mode_t mode)
4417 return 0;
4421 sys_rename_replace (const char *oldname, const char *newname, BOOL force)
4423 BOOL result;
4424 char temp[MAX_UTF8_PATH], temp_a[MAX_PATH];;
4425 int newname_dev;
4426 int oldname_dev;
4427 bool have_temp_a = false;
4429 /* MoveFile on Windows 95 doesn't correctly change the short file name
4430 alias in a number of circumstances (it is not easy to predict when
4431 just by looking at oldname and newname, unfortunately). In these
4432 cases, renaming through a temporary name avoids the problem.
4434 A second problem on Windows 95 is that renaming through a temp name when
4435 newname is uppercase fails (the final long name ends up in
4436 lowercase, although the short alias might be uppercase) UNLESS the
4437 long temp name is not 8.3.
4439 So, on Windows 95 we always rename through a temp name, and we make sure
4440 the temp name has a long extension to ensure correct renaming. */
4442 strcpy (temp, map_w32_filename (oldname, NULL));
4444 /* volume_info is set indirectly by map_w32_filename. */
4445 oldname_dev = volume_info.serialnum;
4447 if (os_subtype == OS_9X)
4449 char * o;
4450 char * p;
4451 int i = 0;
4452 char oldname_a[MAX_PATH];
4454 oldname = map_w32_filename (oldname, NULL);
4455 filename_to_ansi (oldname, oldname_a);
4456 filename_to_ansi (temp, temp_a);
4457 if ((o = strrchr (oldname_a, '\\')))
4458 o++;
4459 else
4460 o = (char *) oldname_a;
4462 if ((p = strrchr (temp_a, '\\')))
4463 p++;
4464 else
4465 p = temp_a;
4469 /* Force temp name to require a manufactured 8.3 alias - this
4470 seems to make the second rename work properly. */
4471 sprintf (p, "_.%s.%d", o, i);
4472 i++;
4473 result = rename (oldname_a, temp_a);
4475 /* This loop must surely terminate! */
4476 while (result < 0 && errno == EEXIST);
4477 if (result < 0)
4478 return -1;
4479 have_temp_a = true;
4482 /* If FORCE, emulate Unix behavior - newname is deleted if it already exists
4483 (at least if it is a file; don't do this for directories).
4485 Since we mustn't do this if we are just changing the case of the
4486 file name (we would end up deleting the file we are trying to
4487 rename!), we let rename detect if the destination file already
4488 exists - that way we avoid the possible pitfalls of trying to
4489 determine ourselves whether two names really refer to the same
4490 file, which is not always possible in the general case. (Consider
4491 all the permutations of shared or subst'd drives, etc.) */
4493 newname = map_w32_filename (newname, NULL);
4495 /* volume_info is set indirectly by map_w32_filename. */
4496 newname_dev = volume_info.serialnum;
4498 if (w32_unicode_filenames)
4500 wchar_t temp_w[MAX_PATH], newname_w[MAX_PATH];
4502 filename_to_utf16 (temp, temp_w);
4503 filename_to_utf16 (newname, newname_w);
4504 result = _wrename (temp_w, newname_w);
4505 if (result < 0)
4507 DWORD w32err = GetLastError ();
4509 if (errno == EACCES
4510 && newname_dev != oldname_dev)
4512 /* The implementation of `rename' on Windows does not return
4513 errno = EXDEV when you are moving a directory to a
4514 different storage device (ex. logical disk). It returns
4515 EACCES instead. So here we handle such situations and
4516 return EXDEV. */
4517 DWORD attributes;
4519 if ((attributes = GetFileAttributesW (temp_w)) != -1
4520 && (attributes & FILE_ATTRIBUTE_DIRECTORY))
4521 errno = EXDEV;
4523 else if (errno == EEXIST && force)
4525 if (_wchmod (newname_w, 0666) != 0)
4526 return result;
4527 if (_wunlink (newname_w) != 0)
4528 return result;
4529 result = _wrename (temp_w, newname_w);
4531 else if (w32err == ERROR_PRIVILEGE_NOT_HELD
4532 && is_symlink (temp))
4534 /* This is Windows prohibiting the user from creating a
4535 symlink in another place, since that requires
4536 privileges. */
4537 errno = EPERM;
4541 else
4543 char newname_a[MAX_PATH];
4545 if (!have_temp_a)
4546 filename_to_ansi (temp, temp_a);
4547 filename_to_ansi (newname, newname_a);
4548 result = rename (temp_a, newname_a);
4549 if (result < 0)
4551 DWORD w32err = GetLastError ();
4553 if (errno == EACCES
4554 && newname_dev != oldname_dev)
4556 DWORD attributes;
4558 if ((attributes = GetFileAttributesA (temp_a)) != -1
4559 && (attributes & FILE_ATTRIBUTE_DIRECTORY))
4560 errno = EXDEV;
4562 else if (errno == EEXIST && force)
4564 if (_chmod (newname_a, 0666) != 0)
4565 return result;
4566 if (_unlink (newname_a) != 0)
4567 return result;
4568 result = rename (temp_a, newname_a);
4570 else if (w32err == ERROR_PRIVILEGE_NOT_HELD
4571 && is_symlink (temp))
4572 errno = EPERM;
4576 return result;
4580 sys_rename (char const *old, char const *new)
4582 return sys_rename_replace (old, new, TRUE);
4586 sys_rmdir (const char * path)
4588 path = map_w32_filename (path, NULL);
4590 if (w32_unicode_filenames)
4592 wchar_t path_w[MAX_PATH];
4594 filename_to_utf16 (path, path_w);
4595 return _wrmdir (path_w);
4597 else
4599 char path_a[MAX_PATH];
4601 filename_to_ansi (path, path_a);
4602 return _rmdir (path_a);
4607 sys_unlink (const char * path)
4609 int rmstatus, e;
4611 path = map_w32_filename (path, NULL);
4613 if (w32_unicode_filenames)
4615 wchar_t path_w[MAX_PATH];
4617 filename_to_utf16 (path, path_w);
4618 /* On Unix, unlink works without write permission. */
4619 _wchmod (path_w, 0666);
4620 rmstatus = _wunlink (path_w);
4621 e = errno;
4622 /* Symlinks to directories can only be deleted by _rmdir;
4623 _unlink returns EACCES. */
4624 if (rmstatus != 0
4625 && errno == EACCES
4626 && (is_symlink (path) & FILE_ATTRIBUTE_DIRECTORY) != 0)
4627 rmstatus = _wrmdir (path_w);
4628 else
4629 errno = e;
4631 else
4633 char path_a[MAX_PATH];
4635 filename_to_ansi (path, path_a);
4636 _chmod (path_a, 0666);
4637 rmstatus = _unlink (path_a);
4638 e = errno;
4639 if (rmstatus != 0
4640 && errno == EACCES
4641 && (is_symlink (path) & FILE_ATTRIBUTE_DIRECTORY) != 0)
4642 rmstatus = _rmdir (path_a);
4643 else
4644 errno = e;
4647 return rmstatus;
4650 static FILETIME utc_base_ft;
4651 static ULONGLONG utc_base; /* In 100ns units */
4652 static int init = 0;
4654 #define FILETIME_TO_U64(result, ft) \
4655 do { \
4656 ULARGE_INTEGER uiTemp; \
4657 uiTemp.LowPart = (ft).dwLowDateTime; \
4658 uiTemp.HighPart = (ft).dwHighDateTime; \
4659 result = uiTemp.QuadPart; \
4660 } while (0)
4662 static void
4663 initialize_utc_base (void)
4665 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
4666 SYSTEMTIME st;
4668 st.wYear = 1970;
4669 st.wMonth = 1;
4670 st.wDay = 1;
4671 st.wHour = 0;
4672 st.wMinute = 0;
4673 st.wSecond = 0;
4674 st.wMilliseconds = 0;
4676 SystemTimeToFileTime (&st, &utc_base_ft);
4677 FILETIME_TO_U64 (utc_base, utc_base_ft);
4680 static time_t
4681 convert_time (FILETIME ft)
4683 ULONGLONG tmp;
4685 if (!init)
4687 initialize_utc_base ();
4688 init = 1;
4691 if (CompareFileTime (&ft, &utc_base_ft) < 0)
4692 return 0;
4694 FILETIME_TO_U64 (tmp, ft);
4695 return (time_t) ((tmp - utc_base) / 10000000L);
4698 static void
4699 convert_from_time_t (time_t time, FILETIME * pft)
4701 ULARGE_INTEGER tmp;
4703 if (!init)
4705 initialize_utc_base ();
4706 init = 1;
4709 /* time in 100ns units since 1-Jan-1601 */
4710 tmp.QuadPart = (ULONGLONG) time * 10000000L + utc_base;
4711 pft->dwHighDateTime = tmp.HighPart;
4712 pft->dwLowDateTime = tmp.LowPart;
4715 static PSECURITY_DESCRIPTOR
4716 get_file_security_desc_by_handle (HANDLE h)
4718 PSECURITY_DESCRIPTOR psd = NULL;
4719 DWORD err;
4720 SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION
4721 | GROUP_SECURITY_INFORMATION /* | DACL_SECURITY_INFORMATION */ ;
4723 err = get_security_info (h, SE_FILE_OBJECT, si,
4724 NULL, NULL, NULL, NULL, &psd);
4725 if (err != ERROR_SUCCESS)
4726 return NULL;
4728 return psd;
4731 static PSECURITY_DESCRIPTOR
4732 get_file_security_desc_by_name (const char *fname)
4734 PSECURITY_DESCRIPTOR psd = NULL;
4735 DWORD sd_len, err;
4736 SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION
4737 | GROUP_SECURITY_INFORMATION /* | DACL_SECURITY_INFORMATION */ ;
4739 if (!get_file_security (fname, si, psd, 0, &sd_len))
4741 err = GetLastError ();
4742 if (err != ERROR_INSUFFICIENT_BUFFER)
4743 return NULL;
4746 psd = xmalloc (sd_len);
4747 if (!get_file_security (fname, si, psd, sd_len, &sd_len))
4749 xfree (psd);
4750 return NULL;
4753 return psd;
4756 static DWORD
4757 get_rid (PSID sid)
4759 unsigned n_subauthorities;
4761 /* Use the last sub-authority value of the RID, the relative
4762 portion of the SID, as user/group ID. */
4763 n_subauthorities = *get_sid_sub_authority_count (sid);
4764 if (n_subauthorities < 1)
4765 return 0; /* the "World" RID */
4766 return *get_sid_sub_authority (sid, n_subauthorities - 1);
4769 /* Caching SID and account values for faster lokup. */
4771 struct w32_id {
4772 unsigned rid;
4773 struct w32_id *next;
4774 char name[GNLEN+1];
4775 unsigned char sid[FLEXIBLE_ARRAY_MEMBER];
4778 static struct w32_id *w32_idlist;
4780 static int
4781 w32_cached_id (PSID sid, unsigned *id, char *name)
4783 struct w32_id *tail, *found;
4785 for (found = NULL, tail = w32_idlist; tail; tail = tail->next)
4787 if (equal_sid ((PSID)tail->sid, sid))
4789 found = tail;
4790 break;
4793 if (found)
4795 *id = found->rid;
4796 strcpy (name, found->name);
4797 return 1;
4799 else
4800 return 0;
4803 static void
4804 w32_add_to_cache (PSID sid, unsigned id, char *name)
4806 DWORD sid_len;
4807 struct w32_id *new_entry;
4809 /* We don't want to leave behind stale cache from when Emacs was
4810 dumped. */
4811 if (initialized)
4813 sid_len = get_length_sid (sid);
4814 new_entry = xmalloc (offsetof (struct w32_id, sid) + sid_len);
4815 if (new_entry)
4817 new_entry->rid = id;
4818 strcpy (new_entry->name, name);
4819 copy_sid (sid_len, (PSID)new_entry->sid, sid);
4820 new_entry->next = w32_idlist;
4821 w32_idlist = new_entry;
4826 #define UID 1
4827 #define GID 2
4829 static int
4830 get_name_and_id (PSECURITY_DESCRIPTOR psd, unsigned *id, char *nm, int what)
4832 PSID sid = NULL;
4833 BOOL dflt;
4834 SID_NAME_USE ignore;
4835 char name[UNLEN+1];
4836 DWORD name_len = sizeof (name);
4837 char domain[1024];
4838 DWORD domain_len = sizeof (domain);
4839 int use_dflt = 0;
4840 int result;
4842 if (what == UID)
4843 result = get_security_descriptor_owner (psd, &sid, &dflt);
4844 else if (what == GID)
4845 result = get_security_descriptor_group (psd, &sid, &dflt);
4846 else
4847 result = 0;
4849 if (!result || !is_valid_sid (sid))
4850 use_dflt = 1;
4851 else if (!w32_cached_id (sid, id, nm))
4853 if (!lookup_account_sid (NULL, sid, name, &name_len,
4854 domain, &domain_len, &ignore)
4855 || name_len > UNLEN+1)
4856 use_dflt = 1;
4857 else
4859 *id = get_rid (sid);
4860 strcpy (nm, name);
4861 w32_add_to_cache (sid, *id, name);
4864 return use_dflt;
4867 static void
4868 get_file_owner_and_group (PSECURITY_DESCRIPTOR psd, struct stat *st)
4870 int dflt_usr = 0, dflt_grp = 0;
4872 if (!psd)
4874 dflt_usr = 1;
4875 dflt_grp = 1;
4877 else
4879 if (get_name_and_id (psd, &st->st_uid, st->st_uname, UID))
4880 dflt_usr = 1;
4881 if (get_name_and_id (psd, &st->st_gid, st->st_gname, GID))
4882 dflt_grp = 1;
4884 /* Consider files to belong to current user/group, if we cannot get
4885 more accurate information. */
4886 if (dflt_usr)
4888 st->st_uid = dflt_passwd.pw_uid;
4889 strcpy (st->st_uname, dflt_passwd.pw_name);
4891 if (dflt_grp)
4893 st->st_gid = dflt_passwd.pw_gid;
4894 strcpy (st->st_gname, dflt_group.gr_name);
4898 /* Return non-zero if NAME is a potentially slow filesystem. */
4899 int is_slow_fs (const char *);
4902 is_slow_fs (const char *name)
4904 char drive_root[4];
4905 UINT devtype;
4907 if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
4908 devtype = DRIVE_REMOTE; /* assume UNC name is remote */
4909 else if (!(strlen (name) >= 2 && IS_DEVICE_SEP (name[1])))
4910 devtype = GetDriveType (NULL); /* use root of current drive */
4911 else
4913 /* GetDriveType needs the root directory of the drive. */
4914 strncpy (drive_root, name, 2);
4915 drive_root[2] = '\\';
4916 drive_root[3] = '\0';
4917 devtype = GetDriveType (drive_root);
4919 return !(devtype == DRIVE_FIXED || devtype == DRIVE_RAMDISK);
4922 /* If this is non-zero, the caller wants accurate information about
4923 file's owner and group, which could be expensive to get. dired.c
4924 uses this flag when needed for the job at hand. */
4925 int w32_stat_get_owner_group;
4927 /* MSVC stat function can't cope with UNC names and has other bugs, so
4928 replace it with our own. This also allows us to calculate consistent
4929 inode values and owner/group without hacks in the main Emacs code,
4930 and support file names encoded in UTF-8. */
4932 static int
4933 stat_worker (const char * path, struct stat * buf, int follow_symlinks)
4935 char *name, *save_name, *r;
4936 WIN32_FIND_DATAW wfd_w;
4937 WIN32_FIND_DATAA wfd_a;
4938 HANDLE fh;
4939 unsigned __int64 fake_inode = 0;
4940 int permission;
4941 int len;
4942 int rootdir = FALSE;
4943 PSECURITY_DESCRIPTOR psd = NULL;
4944 int is_a_symlink = 0;
4945 DWORD file_flags = FILE_FLAG_BACKUP_SEMANTICS;
4946 DWORD access_rights = 0;
4947 DWORD fattrs = 0, serialnum = 0, fs_high = 0, fs_low = 0, nlinks = 1;
4948 FILETIME ctime, atime, wtime;
4949 wchar_t name_w[MAX_PATH];
4950 char name_a[MAX_PATH];
4952 if (path == NULL || buf == NULL)
4954 errno = EFAULT;
4955 return -1;
4958 save_name = name = (char *) map_w32_filename (path, &path);
4959 /* Must be valid filename, no wild cards or other invalid
4960 characters. */
4961 if (strpbrk (name, "*?|<>\""))
4963 errno = ENOENT;
4964 return -1;
4967 len = strlen (name);
4968 /* Allocate 1 extra byte so that we could append a slash to a root
4969 directory, down below. */
4970 name = strcpy (alloca (len + 2), name);
4972 /* Avoid a somewhat costly call to is_symlink if the filesystem
4973 doesn't support symlinks. */
4974 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
4975 is_a_symlink = is_symlink (name);
4977 /* Plan A: Open the file and get all the necessary information via
4978 the resulting handle. This solves several issues in one blow:
4980 . retrieves attributes for the target of a symlink, if needed
4981 . gets attributes of root directories and symlinks pointing to
4982 root directories, thus avoiding the need for special-casing
4983 these and detecting them by examining the file-name format
4984 . retrieves more accurate attributes (e.g., non-zero size for
4985 some directories, esp. directories that are junction points)
4986 . correctly resolves "c:/..", "/.." and similar file names
4987 . avoids run-time penalties for 99% of use cases
4989 Plan A is always tried first, unless the user asked not to (but
4990 if the file is a symlink and we need to follow links, we try Plan
4991 A even if the user asked not to).
4993 If Plan A fails, we go to Plan B (below), where various
4994 potentially expensive techniques must be used to handle "special"
4995 files such as UNC volumes etc. */
4996 if (!(NILP (Vw32_get_true_file_attributes)
4997 || (EQ (Vw32_get_true_file_attributes, Qlocal) && is_slow_fs (name)))
4998 /* Following symlinks requires getting the info by handle. */
4999 || (is_a_symlink && follow_symlinks))
5001 BY_HANDLE_FILE_INFORMATION info;
5003 if (is_a_symlink && !follow_symlinks)
5004 file_flags |= FILE_FLAG_OPEN_REPARSE_POINT;
5005 /* READ_CONTROL access rights are required to get security info
5006 by handle. But if the OS doesn't support security in the
5007 first place, we don't need to try. */
5008 if (is_windows_9x () != TRUE)
5009 access_rights |= READ_CONTROL;
5011 if (w32_unicode_filenames)
5013 filename_to_utf16 (name, name_w);
5014 fh = CreateFileW (name_w, access_rights, 0, NULL, OPEN_EXISTING,
5015 file_flags, NULL);
5016 /* If CreateFile fails with READ_CONTROL, try again with
5017 zero as access rights. */
5018 if (fh == INVALID_HANDLE_VALUE && access_rights)
5019 fh = CreateFileW (name_w, 0, 0, NULL, OPEN_EXISTING,
5020 file_flags, NULL);
5022 else
5024 filename_to_ansi (name, name_a);
5025 fh = CreateFileA (name_a, access_rights, 0, NULL, OPEN_EXISTING,
5026 file_flags, NULL);
5027 if (fh == INVALID_HANDLE_VALUE && access_rights)
5028 fh = CreateFileA (name_a, 0, 0, NULL, OPEN_EXISTING,
5029 file_flags, NULL);
5031 if (fh == INVALID_HANDLE_VALUE)
5032 goto no_true_file_attributes;
5034 /* This is more accurate in terms of getting the correct number
5035 of links, but is quite slow (it is noticeable when Emacs is
5036 making a list of file name completions). */
5037 if (GetFileInformationByHandle (fh, &info))
5039 nlinks = info.nNumberOfLinks;
5040 /* Might as well use file index to fake inode values, but this
5041 is not guaranteed to be unique unless we keep a handle open
5042 all the time (even then there are situations where it is
5043 not unique). Reputedly, there are at most 48 bits of info
5044 (on NTFS, presumably less on FAT). */
5045 fake_inode = info.nFileIndexHigh;
5046 fake_inode <<= 32;
5047 fake_inode += info.nFileIndexLow;
5048 serialnum = info.dwVolumeSerialNumber;
5049 fs_high = info.nFileSizeHigh;
5050 fs_low = info.nFileSizeLow;
5051 ctime = info.ftCreationTime;
5052 atime = info.ftLastAccessTime;
5053 wtime = info.ftLastWriteTime;
5054 fattrs = info.dwFileAttributes;
5056 else
5058 /* We don't go to Plan B here, because it's not clear that
5059 it's a good idea. The only known use case where
5060 CreateFile succeeds, but GetFileInformationByHandle fails
5061 (with ERROR_INVALID_FUNCTION) is for character devices
5062 such as NUL, PRN, etc. For these, switching to Plan B is
5063 a net loss, because we lose the character device
5064 attribute returned by GetFileType below (FindFirstFile
5065 doesn't set that bit in the attributes), and the other
5066 fields don't make sense for character devices anyway.
5067 Emacs doesn't really care for non-file entities in the
5068 context of l?stat, so neither do we. */
5070 /* w32err is assigned so one could put a breakpoint here and
5071 examine its value, when GetFileInformationByHandle
5072 fails. */
5073 DWORD w32err = GetLastError ();
5075 switch (w32err)
5077 case ERROR_FILE_NOT_FOUND: /* can this ever happen? */
5078 errno = ENOENT;
5079 return -1;
5083 /* Test for a symlink before testing for a directory, since
5084 symlinks to directories have the directory bit set, but we
5085 don't want them to appear as directories. */
5086 if (is_a_symlink && !follow_symlinks)
5087 buf->st_mode = S_IFLNK;
5088 else if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
5089 buf->st_mode = S_IFDIR;
5090 else
5092 DWORD ftype = GetFileType (fh);
5094 switch (ftype)
5096 case FILE_TYPE_DISK:
5097 buf->st_mode = S_IFREG;
5098 break;
5099 case FILE_TYPE_PIPE:
5100 buf->st_mode = S_IFIFO;
5101 break;
5102 case FILE_TYPE_CHAR:
5103 case FILE_TYPE_UNKNOWN:
5104 default:
5105 buf->st_mode = S_IFCHR;
5108 /* We produce the fallback owner and group data, based on the
5109 current user that runs Emacs, in the following cases:
5111 . caller didn't request owner and group info
5112 . this is Windows 9X
5113 . getting security by handle failed, and we need to produce
5114 information for the target of a symlink (this is better
5115 than producing a potentially misleading info about the
5116 symlink itself)
5118 If getting security by handle fails, and we don't need to
5119 resolve symlinks, we try getting security by name. */
5120 if (!w32_stat_get_owner_group || is_windows_9x () == TRUE)
5121 get_file_owner_and_group (NULL, buf);
5122 else
5124 psd = get_file_security_desc_by_handle (fh);
5125 if (psd)
5127 get_file_owner_and_group (psd, buf);
5128 LocalFree (psd);
5130 else if (!(is_a_symlink && follow_symlinks))
5132 psd = get_file_security_desc_by_name (name);
5133 get_file_owner_and_group (psd, buf);
5134 xfree (psd);
5136 else
5137 get_file_owner_and_group (NULL, buf);
5139 CloseHandle (fh);
5141 else
5143 no_true_file_attributes:
5144 /* Plan B: Either getting a handle on the file failed, or the
5145 caller explicitly asked us to not bother making this
5146 information more accurate.
5148 Implementation note: In Plan B, we never bother to resolve
5149 symlinks, even if we got here because we tried Plan A and
5150 failed. That's because, even if the caller asked for extra
5151 precision by setting Vw32_get_true_file_attributes to t,
5152 resolving symlinks requires acquiring a file handle to the
5153 symlink, which we already know will fail. And if the user
5154 did not ask for extra precision, resolving symlinks will fly
5155 in the face of that request, since the user then wants the
5156 lightweight version of the code. */
5157 rootdir = (path >= save_name + len - 1
5158 && (IS_DIRECTORY_SEP (*path) || *path == 0));
5160 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
5161 r = IS_DEVICE_SEP (name[1]) ? &name[2] : name;
5162 if (IS_DIRECTORY_SEP (r[0])
5163 && r[1] == '.' && r[2] == '.' && r[3] == '\0')
5164 r[1] = r[2] = '\0';
5166 /* Note: If NAME is a symlink to the root of a UNC volume
5167 (i.e. "\\SERVER"), we will not detect that here, and we will
5168 return data about the symlink as result of FindFirst below.
5169 This is unfortunate, but that marginal use case does not
5170 justify a call to chase_symlinks which would impose a penalty
5171 on all the other use cases. (We get here for symlinks to
5172 roots of UNC volumes because CreateFile above fails for them,
5173 unlike with symlinks to root directories X:\ of drives.) */
5174 if (is_unc_volume (name))
5176 fattrs = unc_volume_file_attributes (name);
5177 if (fattrs == -1)
5178 return -1;
5180 ctime = atime = wtime = utc_base_ft;
5182 else if (rootdir)
5184 /* Make sure root directories end in a slash. */
5185 if (!IS_DIRECTORY_SEP (name[len-1]))
5186 strcpy (name + len, "\\");
5187 if (GetDriveType (name) < 2)
5189 errno = ENOENT;
5190 return -1;
5193 fattrs = FILE_ATTRIBUTE_DIRECTORY;
5194 ctime = atime = wtime = utc_base_ft;
5196 else
5198 int have_wfd = -1;
5200 /* Make sure non-root directories do NOT end in a slash,
5201 otherwise FindFirstFile might fail. */
5202 if (IS_DIRECTORY_SEP (name[len-1]))
5203 name[len - 1] = 0;
5205 /* (This is hacky, but helps when doing file completions on
5206 network drives.) Optimize by using information available from
5207 active readdir if possible. */
5208 len = strlen (dir_pathname);
5209 if (IS_DIRECTORY_SEP (dir_pathname[len-1]))
5210 len--;
5211 if (dir_find_handle != INVALID_HANDLE_VALUE
5212 && last_dir_find_data != -1
5213 && !(is_a_symlink && follow_symlinks)
5214 /* The 2 file-name comparisons below support only ASCII
5215 characters, and will lose (compare not equal) when
5216 the file names include non-ASCII characters that are
5217 the same but for the case. However, doing this
5218 properly involves: (a) converting both file names to
5219 UTF-16, (b) lower-casing both names using CharLowerW,
5220 and (c) comparing the results; this would be quite a
5221 bit slower, whereas Plan B is for users who want
5222 lightweight albeit inaccurate version of 'stat'. */
5223 && c_strncasecmp (save_name, dir_pathname, len) == 0
5224 && IS_DIRECTORY_SEP (name[len])
5225 && xstrcasecmp (name + len + 1, dir_static.d_name) == 0)
5227 have_wfd = last_dir_find_data;
5228 /* This was the last entry returned by readdir. */
5229 if (last_dir_find_data == DIR_FIND_DATA_W)
5230 wfd_w = dir_find_data_w;
5231 else
5232 wfd_a = dir_find_data_a;
5234 else
5236 logon_network_drive (name);
5238 if (w32_unicode_filenames)
5240 filename_to_utf16 (name, name_w);
5241 fh = FindFirstFileW (name_w, &wfd_w);
5242 have_wfd = DIR_FIND_DATA_W;
5244 else
5246 filename_to_ansi (name, name_a);
5247 /* If NAME includes characters not representable by
5248 the current ANSI codepage, filename_to_ansi
5249 usually replaces them with a '?'. We don't want
5250 to let FindFirstFileA interpret those as wildcards,
5251 and "succeed", returning us data from some random
5252 file in the same directory. */
5253 if (_mbspbrk (name_a, "?"))
5254 fh = INVALID_HANDLE_VALUE;
5255 else
5256 fh = FindFirstFileA (name_a, &wfd_a);
5257 have_wfd = DIR_FIND_DATA_A;
5259 if (fh == INVALID_HANDLE_VALUE)
5261 errno = ENOENT;
5262 return -1;
5264 FindClose (fh);
5266 /* Note: if NAME is a symlink, the information we get from
5267 FindFirstFile is for the symlink, not its target. */
5268 if (have_wfd == DIR_FIND_DATA_W)
5270 fattrs = wfd_w.dwFileAttributes;
5271 ctime = wfd_w.ftCreationTime;
5272 atime = wfd_w.ftLastAccessTime;
5273 wtime = wfd_w.ftLastWriteTime;
5274 fs_high = wfd_w.nFileSizeHigh;
5275 fs_low = wfd_w.nFileSizeLow;
5277 else
5279 fattrs = wfd_a.dwFileAttributes;
5280 ctime = wfd_a.ftCreationTime;
5281 atime = wfd_a.ftLastAccessTime;
5282 wtime = wfd_a.ftLastWriteTime;
5283 fs_high = wfd_a.nFileSizeHigh;
5284 fs_low = wfd_a.nFileSizeLow;
5286 fake_inode = 0;
5287 nlinks = 1;
5288 serialnum = volume_info.serialnum;
5290 if (is_a_symlink && !follow_symlinks)
5291 buf->st_mode = S_IFLNK;
5292 else if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
5293 buf->st_mode = S_IFDIR;
5294 else
5295 buf->st_mode = S_IFREG;
5297 get_file_owner_and_group (NULL, buf);
5300 buf->st_ino = fake_inode;
5302 buf->st_dev = serialnum;
5303 buf->st_rdev = serialnum;
5305 buf->st_size = fs_high;
5306 buf->st_size <<= 32;
5307 buf->st_size += fs_low;
5308 buf->st_nlink = nlinks;
5310 /* Convert timestamps to Unix format. */
5311 buf->st_mtime = convert_time (wtime);
5312 buf->st_atime = convert_time (atime);
5313 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
5314 buf->st_ctime = convert_time (ctime);
5315 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
5317 /* determine rwx permissions */
5318 if (is_a_symlink && !follow_symlinks)
5319 permission = S_IREAD | S_IWRITE | S_IEXEC; /* Posix expectations */
5320 else
5322 if (fattrs & FILE_ATTRIBUTE_READONLY)
5323 permission = S_IREAD;
5324 else
5325 permission = S_IREAD | S_IWRITE;
5327 if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
5328 permission |= S_IEXEC;
5329 else if (is_exec (name))
5330 permission |= S_IEXEC;
5333 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
5335 return 0;
5339 stat (const char * path, struct stat * buf)
5341 return stat_worker (path, buf, 1);
5345 lstat (const char * path, struct stat * buf)
5347 return stat_worker (path, buf, 0);
5351 fstatat (int fd, char const *name, struct stat *st, int flags)
5353 /* Rely on a hack: an open directory is modeled as file descriptor 0.
5354 This is good enough for the current usage in Emacs, but is fragile.
5356 FIXME: Add proper support for fdopendir, fstatat, readlinkat.
5357 Gnulib does this and can serve as a model. */
5358 char fullname[MAX_UTF8_PATH];
5360 if (fd != AT_FDCWD)
5362 char lastc = dir_pathname[strlen (dir_pathname) - 1];
5364 if (_snprintf (fullname, sizeof fullname, "%s%s%s",
5365 dir_pathname, IS_DIRECTORY_SEP (lastc) ? "" : "/", name)
5366 < 0)
5368 errno = ENAMETOOLONG;
5369 return -1;
5371 name = fullname;
5374 return stat_worker (name, st, ! (flags & AT_SYMLINK_NOFOLLOW));
5377 /* Provide fstat and utime as well as stat for consistent handling of
5378 file timestamps. */
5380 fstat (int desc, struct stat * buf)
5382 HANDLE fh = (HANDLE) _get_osfhandle (desc);
5383 BY_HANDLE_FILE_INFORMATION info;
5384 unsigned __int64 fake_inode;
5385 int permission;
5387 switch (GetFileType (fh) & ~FILE_TYPE_REMOTE)
5389 case FILE_TYPE_DISK:
5390 buf->st_mode = S_IFREG;
5391 if (!GetFileInformationByHandle (fh, &info))
5393 errno = EACCES;
5394 return -1;
5396 break;
5397 case FILE_TYPE_PIPE:
5398 buf->st_mode = S_IFIFO;
5399 goto non_disk;
5400 case FILE_TYPE_CHAR:
5401 case FILE_TYPE_UNKNOWN:
5402 default:
5403 buf->st_mode = S_IFCHR;
5404 non_disk:
5405 memset (&info, 0, sizeof (info));
5406 info.dwFileAttributes = 0;
5407 info.ftCreationTime = utc_base_ft;
5408 info.ftLastAccessTime = utc_base_ft;
5409 info.ftLastWriteTime = utc_base_ft;
5412 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
5413 buf->st_mode = S_IFDIR;
5415 buf->st_nlink = info.nNumberOfLinks;
5416 /* Might as well use file index to fake inode values, but this
5417 is not guaranteed to be unique unless we keep a handle open
5418 all the time (even then there are situations where it is
5419 not unique). Reputedly, there are at most 48 bits of info
5420 (on NTFS, presumably less on FAT). */
5421 fake_inode = info.nFileIndexHigh;
5422 fake_inode <<= 32;
5423 fake_inode += info.nFileIndexLow;
5425 /* MSVC defines _ino_t to be short; other libc's might not. */
5426 if (sizeof (buf->st_ino) == 2)
5427 buf->st_ino = fake_inode ^ (fake_inode >> 16);
5428 else
5429 buf->st_ino = fake_inode;
5431 /* If the caller so requested, get the true file owner and group.
5432 Otherwise, consider the file to belong to the current user. */
5433 if (!w32_stat_get_owner_group || is_windows_9x () == TRUE)
5434 get_file_owner_and_group (NULL, buf);
5435 else
5437 PSECURITY_DESCRIPTOR psd = NULL;
5439 psd = get_file_security_desc_by_handle (fh);
5440 if (psd)
5442 get_file_owner_and_group (psd, buf);
5443 LocalFree (psd);
5445 else
5446 get_file_owner_and_group (NULL, buf);
5449 buf->st_dev = info.dwVolumeSerialNumber;
5450 buf->st_rdev = info.dwVolumeSerialNumber;
5452 buf->st_size = info.nFileSizeHigh;
5453 buf->st_size <<= 32;
5454 buf->st_size += info.nFileSizeLow;
5456 /* Convert timestamps to Unix format. */
5457 buf->st_mtime = convert_time (info.ftLastWriteTime);
5458 buf->st_atime = convert_time (info.ftLastAccessTime);
5459 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
5460 buf->st_ctime = convert_time (info.ftCreationTime);
5461 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
5463 /* determine rwx permissions */
5464 if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
5465 permission = S_IREAD;
5466 else
5467 permission = S_IREAD | S_IWRITE;
5469 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
5470 permission |= S_IEXEC;
5471 else
5473 #if 0 /* no way of knowing the filename */
5474 char * p = strrchr (name, '.');
5475 if (p != NULL &&
5476 (xstrcasecmp (p, ".exe") == 0 ||
5477 xstrcasecmp (p, ".com") == 0 ||
5478 xstrcasecmp (p, ".bat") == 0 ||
5479 xstrcasecmp (p, ".cmd") == 0))
5480 permission |= S_IEXEC;
5481 #endif
5484 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
5486 return 0;
5489 /* A version of 'utime' which handles directories as well as
5490 files. */
5493 utime (const char *name, struct utimbuf *times)
5495 struct utimbuf deftime;
5496 HANDLE fh;
5497 FILETIME mtime;
5498 FILETIME atime;
5500 if (times == NULL)
5502 deftime.modtime = deftime.actime = time (NULL);
5503 times = &deftime;
5506 if (w32_unicode_filenames)
5508 wchar_t name_utf16[MAX_PATH];
5510 if (filename_to_utf16 (name, name_utf16) != 0)
5511 return -1; /* errno set by filename_to_utf16 */
5513 /* Need write access to set times. */
5514 fh = CreateFileW (name_utf16, FILE_WRITE_ATTRIBUTES,
5515 /* If NAME specifies a directory, FILE_SHARE_DELETE
5516 allows other processes to delete files inside it,
5517 while we have the directory open. */
5518 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
5519 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
5521 else
5523 char name_ansi[MAX_PATH];
5525 if (filename_to_ansi (name, name_ansi) != 0)
5526 return -1; /* errno set by filename_to_ansi */
5528 fh = CreateFileA (name_ansi, FILE_WRITE_ATTRIBUTES,
5529 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
5530 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
5532 if (fh != INVALID_HANDLE_VALUE)
5534 convert_from_time_t (times->actime, &atime);
5535 convert_from_time_t (times->modtime, &mtime);
5536 if (!SetFileTime (fh, NULL, &atime, &mtime))
5538 CloseHandle (fh);
5539 errno = EACCES;
5540 return -1;
5542 CloseHandle (fh);
5544 else
5546 DWORD err = GetLastError ();
5548 switch (err)
5550 case ERROR_FILE_NOT_FOUND:
5551 case ERROR_PATH_NOT_FOUND:
5552 case ERROR_INVALID_DRIVE:
5553 case ERROR_BAD_NETPATH:
5554 case ERROR_DEV_NOT_EXIST:
5555 /* ERROR_INVALID_NAME is the error CreateFile sets when the
5556 file name includes ?s, i.e. translation to ANSI failed. */
5557 case ERROR_INVALID_NAME:
5558 errno = ENOENT;
5559 break;
5560 case ERROR_TOO_MANY_OPEN_FILES:
5561 errno = ENFILE;
5562 break;
5563 case ERROR_ACCESS_DENIED:
5564 case ERROR_SHARING_VIOLATION:
5565 errno = EACCES;
5566 break;
5567 default:
5568 errno = EINVAL;
5569 break;
5571 return -1;
5573 return 0;
5577 sys_umask (int mode)
5579 static int current_mask;
5580 int retval, arg = 0;
5582 /* The only bit we really support is the write bit. Files are
5583 always readable on MS-Windows, and the execute bit does not exist
5584 at all. */
5585 /* FIXME: if the GROUP and OTHER bits are reset, we should use ACLs
5586 to prevent access by other users on NTFS. */
5587 if ((mode & S_IWRITE) != 0)
5588 arg |= S_IWRITE;
5590 retval = _umask (arg);
5591 /* Merge into the return value the bits they've set the last time,
5592 which msvcrt.dll ignores and never returns. Emacs insists on its
5593 notion of mask being identical to what we return. */
5594 retval |= (current_mask & ~S_IWRITE);
5595 current_mask = mode;
5597 return retval;
5601 /* Symlink-related functions. */
5602 #ifndef SYMBOLIC_LINK_FLAG_DIRECTORY
5603 #define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1
5604 #endif
5607 symlink (char const *filename, char const *linkname)
5609 char linkfn[MAX_UTF8_PATH], *tgtfn;
5610 DWORD flags = 0;
5611 int dir_access, filename_ends_in_slash;
5613 /* Diagnostics follows Posix as much as possible. */
5614 if (filename == NULL || linkname == NULL)
5616 errno = EFAULT;
5617 return -1;
5619 if (!*filename)
5621 errno = ENOENT;
5622 return -1;
5624 if (strlen (filename) > MAX_UTF8_PATH || strlen (linkname) > MAX_UTF8_PATH)
5626 errno = ENAMETOOLONG;
5627 return -1;
5630 strcpy (linkfn, map_w32_filename (linkname, NULL));
5631 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) == 0)
5633 errno = EPERM;
5634 return -1;
5637 /* Note: since empty FILENAME was already rejected, we can safely
5638 refer to FILENAME[1]. */
5639 if (!(IS_DIRECTORY_SEP (filename[0]) || IS_DEVICE_SEP (filename[1])))
5641 /* Non-absolute FILENAME is understood as being relative to
5642 LINKNAME's directory. We need to prepend that directory to
5643 FILENAME to get correct results from faccessat below, since
5644 otherwise it will interpret FILENAME relative to the
5645 directory where the Emacs process runs. Note that
5646 make-symbolic-link always makes sure LINKNAME is a fully
5647 expanded file name. */
5648 char tem[MAX_UTF8_PATH];
5649 char *p = linkfn + strlen (linkfn);
5651 while (p > linkfn && !IS_ANY_SEP (p[-1]))
5652 p--;
5653 if (p > linkfn)
5654 strncpy (tem, linkfn, p - linkfn);
5655 strcpy (tem + (p - linkfn), filename);
5656 dir_access = faccessat (AT_FDCWD, tem, D_OK, AT_EACCESS);
5658 else
5659 dir_access = faccessat (AT_FDCWD, filename, D_OK, AT_EACCESS);
5661 /* Since Windows distinguishes between symlinks to directories and
5662 to files, we provide a kludgy feature: if FILENAME doesn't
5663 exist, but ends in a slash, we create a symlink to directory. If
5664 FILENAME exists and is a directory, we always create a symlink to
5665 directory. */
5666 filename_ends_in_slash = IS_DIRECTORY_SEP (filename[strlen (filename) - 1]);
5667 if (dir_access == 0 || filename_ends_in_slash)
5668 flags = SYMBOLIC_LINK_FLAG_DIRECTORY;
5670 tgtfn = (char *)map_w32_filename (filename, NULL);
5671 if (filename_ends_in_slash)
5672 tgtfn[strlen (tgtfn) - 1] = '\0';
5674 errno = 0;
5675 if (!create_symbolic_link (linkfn, tgtfn, flags))
5677 /* ENOSYS is set by create_symbolic_link, when it detects that
5678 the OS doesn't support the CreateSymbolicLink API. */
5679 if (errno != ENOSYS)
5681 DWORD w32err = GetLastError ();
5683 switch (w32err)
5685 /* ERROR_SUCCESS is sometimes returned when LINKFN and
5686 TGTFN point to the same file name, go figure. */
5687 case ERROR_SUCCESS:
5688 case ERROR_FILE_EXISTS:
5689 errno = EEXIST;
5690 break;
5691 case ERROR_ACCESS_DENIED:
5692 errno = EACCES;
5693 break;
5694 case ERROR_FILE_NOT_FOUND:
5695 case ERROR_PATH_NOT_FOUND:
5696 case ERROR_BAD_NETPATH:
5697 case ERROR_INVALID_REPARSE_DATA:
5698 errno = ENOENT;
5699 break;
5700 case ERROR_DIRECTORY:
5701 errno = EISDIR;
5702 break;
5703 case ERROR_PRIVILEGE_NOT_HELD:
5704 case ERROR_NOT_ALL_ASSIGNED:
5705 errno = EPERM;
5706 break;
5707 case ERROR_DISK_FULL:
5708 errno = ENOSPC;
5709 break;
5710 default:
5711 errno = EINVAL;
5712 break;
5715 return -1;
5717 return 0;
5720 /* A quick inexpensive test of whether FILENAME identifies a file that
5721 is a symlink. Returns non-zero if it is, zero otherwise. FILENAME
5722 must already be in the normalized form returned by
5723 map_w32_filename. If the symlink is to a directory, the
5724 FILE_ATTRIBUTE_DIRECTORY bit will be set in the return value.
5726 Note: for repeated operations on many files, it is best to test
5727 whether the underlying volume actually supports symlinks, by
5728 testing the FILE_SUPPORTS_REPARSE_POINTS bit in volume's flags, and
5729 avoid the call to this function if it doesn't. That's because the
5730 call to GetFileAttributes takes a non-negligible time, especially
5731 on non-local or removable filesystems. See stat_worker for an
5732 example of how to do that. */
5733 static int
5734 is_symlink (const char *filename)
5736 DWORD attrs;
5737 wchar_t filename_w[MAX_PATH];
5738 char filename_a[MAX_PATH];
5739 WIN32_FIND_DATAW wfdw;
5740 WIN32_FIND_DATAA wfda;
5741 HANDLE fh;
5742 int attrs_mean_symlink;
5744 if (w32_unicode_filenames)
5746 filename_to_utf16 (filename, filename_w);
5747 attrs = GetFileAttributesW (filename_w);
5749 else
5751 filename_to_ansi (filename, filename_a);
5752 attrs = GetFileAttributesA (filename_a);
5754 if (attrs == -1)
5756 DWORD w32err = GetLastError ();
5758 switch (w32err)
5760 case ERROR_BAD_NETPATH: /* network share, can't be a symlink */
5761 break;
5762 case ERROR_ACCESS_DENIED:
5763 errno = EACCES;
5764 break;
5765 case ERROR_FILE_NOT_FOUND:
5766 case ERROR_PATH_NOT_FOUND:
5767 default:
5768 errno = ENOENT;
5769 break;
5771 return 0;
5773 if ((attrs & FILE_ATTRIBUTE_REPARSE_POINT) == 0)
5774 return 0;
5775 logon_network_drive (filename);
5776 if (w32_unicode_filenames)
5778 fh = FindFirstFileW (filename_w, &wfdw);
5779 attrs_mean_symlink =
5780 (wfdw.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0
5781 && (wfdw.dwReserved0 & IO_REPARSE_TAG_SYMLINK) == IO_REPARSE_TAG_SYMLINK;
5782 if (attrs_mean_symlink)
5783 attrs_mean_symlink |= (wfdw.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
5785 else if (_mbspbrk (filename_a, "?"))
5787 /* filename_to_ansi failed to convert the file name. */
5788 errno = ENOENT;
5789 return 0;
5791 else
5793 fh = FindFirstFileA (filename_a, &wfda);
5794 attrs_mean_symlink =
5795 (wfda.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0
5796 && (wfda.dwReserved0 & IO_REPARSE_TAG_SYMLINK) == IO_REPARSE_TAG_SYMLINK;
5797 if (attrs_mean_symlink)
5798 attrs_mean_symlink |= (wfda.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
5800 if (fh == INVALID_HANDLE_VALUE)
5801 return 0;
5802 FindClose (fh);
5803 return attrs_mean_symlink;
5806 /* If NAME identifies a symbolic link, copy into BUF the file name of
5807 the symlink's target. Copy at most BUF_SIZE bytes, and do NOT
5808 null-terminate the target name, even if it fits. Return the number
5809 of bytes copied, or -1 if NAME is not a symlink or any error was
5810 encountered while resolving it. The file name copied into BUF is
5811 encoded in the current ANSI codepage. */
5812 ssize_t
5813 readlink (const char *name, char *buf, size_t buf_size)
5815 const char *path;
5816 TOKEN_PRIVILEGES privs;
5817 int restore_privs = 0;
5818 HANDLE sh;
5819 ssize_t retval;
5820 char resolved[MAX_UTF8_PATH];
5822 if (name == NULL)
5824 errno = EFAULT;
5825 return -1;
5827 if (!*name)
5829 errno = ENOENT;
5830 return -1;
5833 path = map_w32_filename (name, NULL);
5835 if (strlen (path) > MAX_UTF8_PATH)
5837 errno = ENAMETOOLONG;
5838 return -1;
5841 errno = 0;
5842 if (is_windows_9x () == TRUE
5843 || (volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) == 0
5844 || !is_symlink (path))
5846 if (!errno)
5847 errno = EINVAL; /* not a symlink */
5848 return -1;
5851 /* Done with simple tests, now we're in for some _real_ work. */
5852 if (enable_privilege (SE_BACKUP_NAME, TRUE, &privs))
5853 restore_privs = 1;
5854 /* Implementation note: From here and onward, don't return early,
5855 since that will fail to restore the original set of privileges of
5856 the calling thread. */
5858 retval = -1; /* not too optimistic, are we? */
5860 /* Note: In the next call to CreateFile, we use zero as the 2nd
5861 argument because, when the symlink is a hidden/system file,
5862 e.g. 'C:\Users\All Users', GENERIC_READ fails with
5863 ERROR_ACCESS_DENIED. Zero seems to work just fine, both for file
5864 and directory symlinks. */
5865 if (w32_unicode_filenames)
5867 wchar_t path_w[MAX_PATH];
5869 filename_to_utf16 (path, path_w);
5870 sh = CreateFileW (path_w, 0, 0, NULL, OPEN_EXISTING,
5871 FILE_FLAG_OPEN_REPARSE_POINT
5872 | FILE_FLAG_BACKUP_SEMANTICS,
5873 NULL);
5875 else
5877 char path_a[MAX_PATH];
5879 filename_to_ansi (path, path_a);
5880 sh = CreateFileA (path_a, 0, 0, NULL, OPEN_EXISTING,
5881 FILE_FLAG_OPEN_REPARSE_POINT
5882 | FILE_FLAG_BACKUP_SEMANTICS,
5883 NULL);
5885 if (sh != INVALID_HANDLE_VALUE)
5887 BYTE reparse_buf[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
5888 REPARSE_DATA_BUFFER *reparse_data = (REPARSE_DATA_BUFFER *)&reparse_buf[0];
5889 DWORD retbytes;
5891 if (!DeviceIoControl (sh, FSCTL_GET_REPARSE_POINT, NULL, 0,
5892 reparse_buf, MAXIMUM_REPARSE_DATA_BUFFER_SIZE,
5893 &retbytes, NULL))
5894 errno = EIO;
5895 else if (reparse_data->ReparseTag != IO_REPARSE_TAG_SYMLINK)
5896 errno = EINVAL;
5897 else
5899 /* Copy the link target name, in wide characters, from
5900 reparse_data, then convert it to multibyte encoding in
5901 the current locale's codepage. */
5902 WCHAR *lwname;
5903 size_t lname_size;
5904 USHORT lwname_len =
5905 reparse_data->SymbolicLinkReparseBuffer.PrintNameLength;
5906 WCHAR *lwname_src =
5907 reparse_data->SymbolicLinkReparseBuffer.PathBuffer
5908 + reparse_data->SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(WCHAR);
5909 size_t size_to_copy = buf_size;
5911 /* According to MSDN, PrintNameLength does not include the
5912 terminating null character. */
5913 lwname = alloca ((lwname_len + 1) * sizeof(WCHAR));
5914 memcpy (lwname, lwname_src, lwname_len);
5915 lwname[lwname_len/sizeof(WCHAR)] = 0; /* null-terminate */
5916 filename_from_utf16 (lwname, resolved);
5917 dostounix_filename (resolved);
5918 lname_size = strlen (resolved) + 1;
5919 if (lname_size <= buf_size)
5920 size_to_copy = lname_size;
5921 strncpy (buf, resolved, size_to_copy);
5922 /* Success! */
5923 retval = size_to_copy;
5925 CloseHandle (sh);
5927 else
5929 /* CreateFile failed. */
5930 DWORD w32err2 = GetLastError ();
5932 switch (w32err2)
5934 case ERROR_FILE_NOT_FOUND:
5935 case ERROR_PATH_NOT_FOUND:
5936 errno = ENOENT;
5937 break;
5938 case ERROR_ACCESS_DENIED:
5939 case ERROR_TOO_MANY_OPEN_FILES:
5940 errno = EACCES;
5941 break;
5942 default:
5943 errno = EPERM;
5944 break;
5947 if (restore_privs)
5949 restore_privilege (&privs);
5950 revert_to_self ();
5953 return retval;
5956 ssize_t
5957 readlinkat (int fd, char const *name, char *buffer,
5958 size_t buffer_size)
5960 /* Rely on a hack: an open directory is modeled as file descriptor 0,
5961 as in fstatat. FIXME: Add proper support for readlinkat. */
5962 char fullname[MAX_UTF8_PATH];
5964 if (fd != AT_FDCWD)
5966 if (_snprintf (fullname, sizeof fullname, "%s/%s", dir_pathname, name)
5967 < 0)
5969 errno = ENAMETOOLONG;
5970 return -1;
5972 name = fullname;
5975 return readlink (name, buffer, buffer_size);
5978 /* If FILE is a symlink, return its target (stored in a static
5979 buffer); otherwise return FILE.
5981 This function repeatedly resolves symlinks in the last component of
5982 a chain of symlink file names, as in foo -> bar -> baz -> ...,
5983 until it arrives at a file whose last component is not a symlink,
5984 or some error occurs. It returns the target of the last
5985 successfully resolved symlink in the chain. If it succeeds to
5986 resolve even a single symlink, the value returned is an absolute
5987 file name with backslashes (result of GetFullPathName). By
5988 contrast, if the original FILE is returned, it is unaltered.
5990 Note: This function can set errno even if it succeeds.
5992 Implementation note: we only resolve the last portion ("basename")
5993 of the argument FILE and of each following file in the chain,
5994 disregarding any possible symlinks in its leading directories.
5995 This is because Windows system calls and library functions
5996 transparently resolve symlinks in leading directories and return
5997 correct information, as long as the basename is not a symlink. */
5998 static char *
5999 chase_symlinks (const char *file)
6001 static char target[MAX_UTF8_PATH];
6002 char link[MAX_UTF8_PATH];
6003 wchar_t target_w[MAX_PATH], link_w[MAX_PATH];
6004 char target_a[MAX_PATH], link_a[MAX_PATH];
6005 ssize_t res, link_len;
6006 int loop_count = 0;
6008 if (is_windows_9x () == TRUE || !is_symlink (file))
6009 return (char *)file;
6011 if (w32_unicode_filenames)
6013 wchar_t file_w[MAX_PATH];
6015 filename_to_utf16 (file, file_w);
6016 if (GetFullPathNameW (file_w, MAX_PATH, link_w, NULL) == 0)
6017 return (char *)file;
6018 filename_from_utf16 (link_w, link);
6020 else
6022 char file_a[MAX_PATH];
6024 filename_to_ansi (file, file_a);
6025 if (GetFullPathNameA (file_a, MAX_PATH, link_a, NULL) == 0)
6026 return (char *)file;
6027 filename_from_ansi (link_a, link);
6029 link_len = strlen (link);
6031 target[0] = '\0';
6032 do {
6034 /* Remove trailing slashes, as we want to resolve the last
6035 non-trivial part of the link name. */
6036 while (link_len > 3 && IS_DIRECTORY_SEP (link[link_len-1]))
6037 link[link_len--] = '\0';
6039 res = readlink (link, target, MAX_UTF8_PATH);
6040 if (res > 0)
6042 target[res] = '\0';
6043 if (!(IS_DEVICE_SEP (target[1])
6044 || (IS_DIRECTORY_SEP (target[0]) && IS_DIRECTORY_SEP (target[1]))))
6046 /* Target is relative. Append it to the directory part of
6047 the symlink, then copy the result back to target. */
6048 char *p = link + link_len;
6050 while (p > link && !IS_ANY_SEP (p[-1]))
6051 p--;
6052 strcpy (p, target);
6053 strcpy (target, link);
6055 /* Resolve any "." and ".." to get a fully-qualified file name
6056 in link[] again. */
6057 if (w32_unicode_filenames)
6059 filename_to_utf16 (target, target_w);
6060 link_len = GetFullPathNameW (target_w, MAX_PATH, link_w, NULL);
6061 if (link_len > 0)
6062 filename_from_utf16 (link_w, link);
6064 else
6066 filename_to_ansi (target, target_a);
6067 link_len = GetFullPathNameA (target_a, MAX_PATH, link_a, NULL);
6068 if (link_len > 0)
6069 filename_from_ansi (link_a, link);
6071 link_len = strlen (link);
6073 } while (res > 0 && link_len > 0 && ++loop_count <= 100);
6075 if (loop_count > 100)
6076 errno = ELOOP;
6078 if (target[0] == '\0') /* not a single call to readlink succeeded */
6079 return (char *)file;
6080 return target;
6084 /* Posix ACL emulation. */
6087 acl_valid (acl_t acl)
6089 return is_valid_security_descriptor ((PSECURITY_DESCRIPTOR)acl) ? 0 : -1;
6092 char *
6093 acl_to_text (acl_t acl, ssize_t *size)
6095 LPTSTR str_acl;
6096 SECURITY_INFORMATION flags =
6097 OWNER_SECURITY_INFORMATION |
6098 GROUP_SECURITY_INFORMATION |
6099 DACL_SECURITY_INFORMATION;
6100 char *retval = NULL;
6101 ULONG local_size;
6102 int e = errno;
6104 errno = 0;
6106 if (convert_sd_to_sddl ((PSECURITY_DESCRIPTOR)acl, SDDL_REVISION_1, flags, &str_acl, &local_size))
6108 errno = e;
6109 /* We don't want to mix heaps, so we duplicate the string in our
6110 heap and free the one allocated by the API. */
6111 retval = xstrdup (str_acl);
6112 if (size)
6113 *size = local_size;
6114 LocalFree (str_acl);
6116 else if (errno != ENOTSUP)
6117 errno = EINVAL;
6119 return retval;
6122 acl_t
6123 acl_from_text (const char *acl_str)
6125 PSECURITY_DESCRIPTOR psd, retval = NULL;
6126 ULONG sd_size;
6127 int e = errno;
6129 errno = 0;
6131 if (convert_sddl_to_sd (acl_str, SDDL_REVISION_1, &psd, &sd_size))
6133 errno = e;
6134 retval = xmalloc (sd_size);
6135 memcpy (retval, psd, sd_size);
6136 LocalFree (psd);
6138 else if (errno != ENOTSUP)
6139 errno = EINVAL;
6141 return retval;
6145 acl_free (void *ptr)
6147 xfree (ptr);
6148 return 0;
6151 acl_t
6152 acl_get_file (const char *fname, acl_type_t type)
6154 PSECURITY_DESCRIPTOR psd = NULL;
6155 const char *filename;
6157 if (type == ACL_TYPE_ACCESS)
6159 DWORD sd_len, err;
6160 SECURITY_INFORMATION si =
6161 OWNER_SECURITY_INFORMATION |
6162 GROUP_SECURITY_INFORMATION |
6163 DACL_SECURITY_INFORMATION ;
6164 int e = errno;
6166 filename = map_w32_filename (fname, NULL);
6167 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
6168 fname = chase_symlinks (filename);
6169 else
6170 fname = filename;
6172 errno = 0;
6173 if (!get_file_security (fname, si, psd, 0, &sd_len)
6174 && errno != ENOTSUP)
6176 err = GetLastError ();
6177 if (err == ERROR_INSUFFICIENT_BUFFER)
6179 psd = xmalloc (sd_len);
6180 if (!get_file_security (fname, si, psd, sd_len, &sd_len))
6182 xfree (psd);
6183 errno = EIO;
6184 psd = NULL;
6187 else if (err == ERROR_FILE_NOT_FOUND
6188 || err == ERROR_PATH_NOT_FOUND
6189 /* ERROR_INVALID_NAME is what we get if
6190 w32-unicode-filenames is nil and the file cannot
6191 be encoded in the current ANSI codepage. */
6192 || err == ERROR_INVALID_NAME)
6193 errno = ENOENT;
6194 else
6195 errno = EIO;
6197 else if (!errno)
6198 errno = e;
6200 else if (type != ACL_TYPE_DEFAULT)
6201 errno = EINVAL;
6203 return psd;
6207 acl_set_file (const char *fname, acl_type_t type, acl_t acl)
6209 TOKEN_PRIVILEGES old1, old2;
6210 DWORD err;
6211 int st = 0, retval = -1;
6212 SECURITY_INFORMATION flags = 0;
6213 PSID psidOwner, psidGroup;
6214 PACL pacl;
6215 BOOL dflt;
6216 BOOL dacl_present;
6217 int e;
6218 const char *filename;
6220 if (acl_valid (acl) != 0
6221 || (type != ACL_TYPE_DEFAULT && type != ACL_TYPE_ACCESS))
6223 errno = EINVAL;
6224 return -1;
6227 if (type == ACL_TYPE_DEFAULT)
6229 errno = ENOSYS;
6230 return -1;
6233 filename = map_w32_filename (fname, NULL);
6234 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
6235 fname = chase_symlinks (filename);
6236 else
6237 fname = filename;
6239 if (get_security_descriptor_owner ((PSECURITY_DESCRIPTOR)acl, &psidOwner,
6240 &dflt)
6241 && psidOwner)
6242 flags |= OWNER_SECURITY_INFORMATION;
6243 if (get_security_descriptor_group ((PSECURITY_DESCRIPTOR)acl, &psidGroup,
6244 &dflt)
6245 && psidGroup)
6246 flags |= GROUP_SECURITY_INFORMATION;
6247 if (get_security_descriptor_dacl ((PSECURITY_DESCRIPTOR)acl, &dacl_present,
6248 &pacl, &dflt)
6249 && dacl_present)
6250 flags |= DACL_SECURITY_INFORMATION;
6251 if (!flags)
6252 return 0;
6254 /* According to KB-245153, setting the owner will succeed if either:
6255 (1) the caller is the user who will be the new owner, and has the
6256 SE_TAKE_OWNERSHIP privilege, or
6257 (2) the caller has the SE_RESTORE privilege, in which case she can
6258 set any valid user or group as the owner
6260 We request below both SE_TAKE_OWNERSHIP and SE_RESTORE
6261 privileges, and disregard any failures in obtaining them. If
6262 these privileges cannot be obtained, and do not already exist in
6263 the calling thread's security token, this function could fail
6264 with EPERM. */
6265 if (enable_privilege (SE_TAKE_OWNERSHIP_NAME, TRUE, &old1))
6266 st++;
6267 if (enable_privilege (SE_RESTORE_NAME, TRUE, &old2))
6268 st++;
6270 e = errno;
6271 errno = 0;
6272 /* SetFileSecurity is deprecated by MS, and sometimes fails when
6273 DACL inheritance is involved, but it seems to preserve ownership
6274 better than SetNamedSecurityInfo, which is important e.g., in
6275 copy-file. */
6276 if (!set_file_security (fname, flags, (PSECURITY_DESCRIPTOR)acl))
6278 err = GetLastError ();
6280 if (errno != ENOTSUP)
6281 err = set_named_security_info (fname, SE_FILE_OBJECT, flags,
6282 psidOwner, psidGroup, pacl, NULL);
6284 else
6285 err = ERROR_SUCCESS;
6286 if (err != ERROR_SUCCESS)
6288 if (errno == ENOTSUP)
6290 else if (err == ERROR_INVALID_OWNER
6291 || err == ERROR_NOT_ALL_ASSIGNED
6292 || err == ERROR_ACCESS_DENIED)
6294 /* Maybe the requested ACL and the one the file already has
6295 are identical, in which case we can silently ignore the
6296 failure. (And no, Windows doesn't.) */
6297 acl_t current_acl = acl_get_file (fname, ACL_TYPE_ACCESS);
6299 errno = EPERM;
6300 if (current_acl)
6302 char *acl_from = acl_to_text (current_acl, NULL);
6303 char *acl_to = acl_to_text (acl, NULL);
6305 if (acl_from && acl_to && xstrcasecmp (acl_from, acl_to) == 0)
6307 retval = 0;
6308 errno = e;
6310 if (acl_from)
6311 acl_free (acl_from);
6312 if (acl_to)
6313 acl_free (acl_to);
6314 acl_free (current_acl);
6317 else if (err == ERROR_FILE_NOT_FOUND
6318 || err == ERROR_PATH_NOT_FOUND
6319 /* ERROR_INVALID_NAME is what we get if
6320 w32-unicode-filenames is nil and the file cannot be
6321 encoded in the current ANSI codepage. */
6322 || err == ERROR_INVALID_NAME)
6323 errno = ENOENT;
6324 else
6325 errno = EACCES;
6327 else
6329 retval = 0;
6330 errno = e;
6333 if (st)
6335 if (st >= 2)
6336 restore_privilege (&old2);
6337 restore_privilege (&old1);
6338 revert_to_self ();
6341 return retval;
6344 /* Return true if errno value ERRNUM indicates that ACLs are well
6345 supported on this system. ERRNUM should be an errno value obtained
6346 after an ACL-related system call fails. */
6347 bool
6348 acl_errno_valid (int errnum)
6350 switch (errnum)
6352 case EBUSY:
6353 case EINVAL:
6354 case ENOTSUP:
6355 return false;
6356 default:
6357 return true;
6362 /* MS-Windows version of careadlinkat (cf. ../lib/careadlinkat.c). We
6363 have a fixed max size for file names, so we don't need the kind of
6364 alloc/malloc/realloc dance the gnulib version does. We also don't
6365 support FD-relative symlinks. */
6366 char *
6367 careadlinkat (int fd, char const *filename,
6368 char *buffer, size_t buffer_size,
6369 struct allocator const *alloc,
6370 ssize_t (*preadlinkat) (int, char const *, char *, size_t))
6372 char linkname[MAX_UTF8_PATH];
6373 ssize_t link_size;
6375 link_size = preadlinkat (fd, filename, linkname, sizeof(linkname));
6377 if (link_size > 0)
6379 char *retval = buffer;
6381 linkname[link_size++] = '\0';
6382 if (link_size > buffer_size)
6383 retval = (char *)(alloc ? alloc->allocate : xmalloc) (link_size);
6384 if (retval)
6385 memcpy (retval, linkname, link_size);
6387 return retval;
6389 return NULL;
6393 w32_copy_file (const char *from, const char *to,
6394 int keep_time, int preserve_ownership, int copy_acls)
6396 acl_t acl = NULL;
6397 BOOL copy_result;
6398 wchar_t from_w[MAX_PATH], to_w[MAX_PATH];
6399 char from_a[MAX_PATH], to_a[MAX_PATH];
6401 /* We ignore preserve_ownership for now. */
6402 preserve_ownership = preserve_ownership;
6404 if (copy_acls)
6406 acl = acl_get_file (from, ACL_TYPE_ACCESS);
6407 if (acl == NULL && acl_errno_valid (errno))
6408 return -2;
6410 if (w32_unicode_filenames)
6412 filename_to_utf16 (from, from_w);
6413 filename_to_utf16 (to, to_w);
6414 copy_result = CopyFileW (from_w, to_w, FALSE);
6416 else
6418 filename_to_ansi (from, from_a);
6419 filename_to_ansi (to, to_a);
6420 copy_result = CopyFileA (from_a, to_a, FALSE);
6422 if (!copy_result)
6424 /* CopyFile doesn't set errno when it fails. By far the most
6425 "popular" reason is that the target is read-only. */
6426 DWORD err = GetLastError ();
6428 switch (err)
6430 case ERROR_FILE_NOT_FOUND:
6431 errno = ENOENT;
6432 break;
6433 case ERROR_ACCESS_DENIED:
6434 errno = EACCES;
6435 break;
6436 case ERROR_ENCRYPTION_FAILED:
6437 errno = EIO;
6438 break;
6439 default:
6440 errno = EPERM;
6441 break;
6444 if (acl)
6445 acl_free (acl);
6446 return -1;
6448 /* CopyFile retains the timestamp by default. However, see
6449 "Community Additions" for CopyFile: it sounds like that is not
6450 entirely true. Testing on Windows XP confirms that modified time
6451 is copied, but creation and last-access times are not.
6452 FIXME? */
6453 else if (!keep_time)
6455 struct timespec now;
6456 DWORD attributes;
6458 if (w32_unicode_filenames)
6460 /* Ensure file is writable while its times are set. */
6461 attributes = GetFileAttributesW (to_w);
6462 SetFileAttributesW (to_w, attributes & ~FILE_ATTRIBUTE_READONLY);
6463 now = current_timespec ();
6464 if (set_file_times (-1, to, now, now))
6466 /* Restore original attributes. */
6467 SetFileAttributesW (to_w, attributes);
6468 if (acl)
6469 acl_free (acl);
6470 return -3;
6472 /* Restore original attributes. */
6473 SetFileAttributesW (to_w, attributes);
6475 else
6477 attributes = GetFileAttributesA (to_a);
6478 SetFileAttributesA (to_a, attributes & ~FILE_ATTRIBUTE_READONLY);
6479 now = current_timespec ();
6480 if (set_file_times (-1, to, now, now))
6482 SetFileAttributesA (to_a, attributes);
6483 if (acl)
6484 acl_free (acl);
6485 return -3;
6487 SetFileAttributesA (to_a, attributes);
6490 if (acl != NULL)
6492 bool fail =
6493 acl_set_file (to, ACL_TYPE_ACCESS, acl) != 0;
6494 acl_free (acl);
6495 if (fail && acl_errno_valid (errno))
6496 return -4;
6499 return 0;
6503 /* Support for browsing other processes and their attributes. See
6504 process.c for the Lisp bindings. */
6506 /* Helper wrapper functions. */
6508 static HANDLE WINAPI
6509 create_toolhelp32_snapshot (DWORD Flags, DWORD Ignored)
6511 static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot = NULL;
6513 if (g_b_init_create_toolhelp32_snapshot == 0)
6515 g_b_init_create_toolhelp32_snapshot = 1;
6516 s_pfn_Create_Toolhelp32_Snapshot = (CreateToolhelp32Snapshot_Proc)
6517 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6518 "CreateToolhelp32Snapshot");
6520 if (s_pfn_Create_Toolhelp32_Snapshot == NULL)
6522 return INVALID_HANDLE_VALUE;
6524 return (s_pfn_Create_Toolhelp32_Snapshot (Flags, Ignored));
6527 static BOOL WINAPI
6528 process32_first (HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
6530 static Process32First_Proc s_pfn_Process32_First = NULL;
6532 if (g_b_init_process32_first == 0)
6534 g_b_init_process32_first = 1;
6535 s_pfn_Process32_First = (Process32First_Proc)
6536 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6537 "Process32First");
6539 if (s_pfn_Process32_First == NULL)
6541 return FALSE;
6543 return (s_pfn_Process32_First (hSnapshot, lppe));
6546 static BOOL WINAPI
6547 process32_next (HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
6549 static Process32Next_Proc s_pfn_Process32_Next = NULL;
6551 if (g_b_init_process32_next == 0)
6553 g_b_init_process32_next = 1;
6554 s_pfn_Process32_Next = (Process32Next_Proc)
6555 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6556 "Process32Next");
6558 if (s_pfn_Process32_Next == NULL)
6560 return FALSE;
6562 return (s_pfn_Process32_Next (hSnapshot, lppe));
6565 static BOOL WINAPI
6566 open_thread_token (HANDLE ThreadHandle,
6567 DWORD DesiredAccess,
6568 BOOL OpenAsSelf,
6569 PHANDLE TokenHandle)
6571 static OpenThreadToken_Proc s_pfn_Open_Thread_Token = NULL;
6572 HMODULE hm_advapi32 = NULL;
6573 if (is_windows_9x () == TRUE)
6575 SetLastError (ERROR_NOT_SUPPORTED);
6576 return FALSE;
6578 if (g_b_init_open_thread_token == 0)
6580 g_b_init_open_thread_token = 1;
6581 hm_advapi32 = LoadLibrary ("Advapi32.dll");
6582 s_pfn_Open_Thread_Token =
6583 (OpenThreadToken_Proc) GetProcAddress (hm_advapi32, "OpenThreadToken");
6585 if (s_pfn_Open_Thread_Token == NULL)
6587 SetLastError (ERROR_NOT_SUPPORTED);
6588 return FALSE;
6590 return (
6591 s_pfn_Open_Thread_Token (
6592 ThreadHandle,
6593 DesiredAccess,
6594 OpenAsSelf,
6595 TokenHandle)
6599 static BOOL WINAPI
6600 impersonate_self (SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
6602 static ImpersonateSelf_Proc s_pfn_Impersonate_Self = NULL;
6603 HMODULE hm_advapi32 = NULL;
6604 if (is_windows_9x () == TRUE)
6606 return FALSE;
6608 if (g_b_init_impersonate_self == 0)
6610 g_b_init_impersonate_self = 1;
6611 hm_advapi32 = LoadLibrary ("Advapi32.dll");
6612 s_pfn_Impersonate_Self =
6613 (ImpersonateSelf_Proc) GetProcAddress (hm_advapi32, "ImpersonateSelf");
6615 if (s_pfn_Impersonate_Self == NULL)
6617 return FALSE;
6619 return s_pfn_Impersonate_Self (ImpersonationLevel);
6622 static BOOL WINAPI
6623 revert_to_self (void)
6625 static RevertToSelf_Proc s_pfn_Revert_To_Self = NULL;
6626 HMODULE hm_advapi32 = NULL;
6627 if (is_windows_9x () == TRUE)
6629 return FALSE;
6631 if (g_b_init_revert_to_self == 0)
6633 g_b_init_revert_to_self = 1;
6634 hm_advapi32 = LoadLibrary ("Advapi32.dll");
6635 s_pfn_Revert_To_Self =
6636 (RevertToSelf_Proc) GetProcAddress (hm_advapi32, "RevertToSelf");
6638 if (s_pfn_Revert_To_Self == NULL)
6640 return FALSE;
6642 return s_pfn_Revert_To_Self ();
6645 static BOOL WINAPI
6646 get_process_memory_info (HANDLE h_proc,
6647 PPROCESS_MEMORY_COUNTERS mem_counters,
6648 DWORD bufsize)
6650 static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info = NULL;
6651 HMODULE hm_psapi = NULL;
6652 if (is_windows_9x () == TRUE)
6654 return FALSE;
6656 if (g_b_init_get_process_memory_info == 0)
6658 g_b_init_get_process_memory_info = 1;
6659 hm_psapi = LoadLibrary ("Psapi.dll");
6660 if (hm_psapi)
6661 s_pfn_Get_Process_Memory_Info = (GetProcessMemoryInfo_Proc)
6662 GetProcAddress (hm_psapi, "GetProcessMemoryInfo");
6664 if (s_pfn_Get_Process_Memory_Info == NULL)
6666 return FALSE;
6668 return s_pfn_Get_Process_Memory_Info (h_proc, mem_counters, bufsize);
6671 static BOOL WINAPI
6672 get_process_working_set_size (HANDLE h_proc,
6673 PSIZE_T minrss,
6674 PSIZE_T maxrss)
6676 static GetProcessWorkingSetSize_Proc
6677 s_pfn_Get_Process_Working_Set_Size = NULL;
6679 if (is_windows_9x () == TRUE)
6681 return FALSE;
6683 if (g_b_init_get_process_working_set_size == 0)
6685 g_b_init_get_process_working_set_size = 1;
6686 s_pfn_Get_Process_Working_Set_Size = (GetProcessWorkingSetSize_Proc)
6687 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6688 "GetProcessWorkingSetSize");
6690 if (s_pfn_Get_Process_Working_Set_Size == NULL)
6692 return FALSE;
6694 return s_pfn_Get_Process_Working_Set_Size (h_proc, minrss, maxrss);
6697 static BOOL WINAPI
6698 global_memory_status (MEMORYSTATUS *buf)
6700 static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status = NULL;
6702 if (is_windows_9x () == TRUE)
6704 return FALSE;
6706 if (g_b_init_global_memory_status == 0)
6708 g_b_init_global_memory_status = 1;
6709 s_pfn_Global_Memory_Status = (GlobalMemoryStatus_Proc)
6710 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6711 "GlobalMemoryStatus");
6713 if (s_pfn_Global_Memory_Status == NULL)
6715 return FALSE;
6717 return s_pfn_Global_Memory_Status (buf);
6720 static BOOL WINAPI
6721 global_memory_status_ex (MEMORY_STATUS_EX *buf)
6723 static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex = NULL;
6725 if (is_windows_9x () == TRUE)
6727 return FALSE;
6729 if (g_b_init_global_memory_status_ex == 0)
6731 g_b_init_global_memory_status_ex = 1;
6732 s_pfn_Global_Memory_Status_Ex = (GlobalMemoryStatusEx_Proc)
6733 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6734 "GlobalMemoryStatusEx");
6736 if (s_pfn_Global_Memory_Status_Ex == NULL)
6738 return FALSE;
6740 return s_pfn_Global_Memory_Status_Ex (buf);
6743 Lisp_Object
6744 list_system_processes (void)
6746 Lisp_Object proclist = Qnil;
6747 HANDLE h_snapshot;
6749 h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
6751 if (h_snapshot != INVALID_HANDLE_VALUE)
6753 PROCESSENTRY32 proc_entry;
6754 DWORD proc_id;
6755 BOOL res;
6757 proc_entry.dwSize = sizeof (PROCESSENTRY32);
6758 for (res = process32_first (h_snapshot, &proc_entry); res;
6759 res = process32_next (h_snapshot, &proc_entry))
6761 proc_id = proc_entry.th32ProcessID;
6762 proclist = Fcons (make_fixnum_or_float (proc_id), proclist);
6765 CloseHandle (h_snapshot);
6766 proclist = Fnreverse (proclist);
6769 return proclist;
6772 static int
6773 enable_privilege (LPCTSTR priv_name, BOOL enable_p, TOKEN_PRIVILEGES *old_priv)
6775 TOKEN_PRIVILEGES priv;
6776 DWORD priv_size = sizeof (priv);
6777 DWORD opriv_size = sizeof (*old_priv);
6778 HANDLE h_token = NULL;
6779 HANDLE h_thread = GetCurrentThread ();
6780 int ret_val = 0;
6781 BOOL res;
6783 res = open_thread_token (h_thread,
6784 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
6785 FALSE, &h_token);
6786 if (!res && GetLastError () == ERROR_NO_TOKEN)
6788 if (impersonate_self (SecurityImpersonation))
6789 res = open_thread_token (h_thread,
6790 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
6791 FALSE, &h_token);
6793 if (res)
6795 priv.PrivilegeCount = 1;
6796 priv.Privileges[0].Attributes = enable_p ? SE_PRIVILEGE_ENABLED : 0;
6797 LookupPrivilegeValue (NULL, priv_name, &priv.Privileges[0].Luid);
6798 if (AdjustTokenPrivileges (h_token, FALSE, &priv, priv_size,
6799 old_priv, &opriv_size)
6800 && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
6801 ret_val = 1;
6803 if (h_token)
6804 CloseHandle (h_token);
6806 return ret_val;
6809 static int
6810 restore_privilege (TOKEN_PRIVILEGES *priv)
6812 DWORD priv_size = sizeof (*priv);
6813 HANDLE h_token = NULL;
6814 int ret_val = 0;
6816 if (open_thread_token (GetCurrentThread (),
6817 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
6818 FALSE, &h_token))
6820 if (AdjustTokenPrivileges (h_token, FALSE, priv, priv_size, NULL, NULL)
6821 && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
6822 ret_val = 1;
6824 if (h_token)
6825 CloseHandle (h_token);
6827 return ret_val;
6830 static Lisp_Object
6831 ltime (ULONGLONG time_100ns)
6833 ULONGLONG time_sec = time_100ns / 10000000;
6834 int subsec = time_100ns % 10000000;
6835 return list4i (time_sec >> 16, time_sec & 0xffff,
6836 subsec / 10, subsec % 10 * 100000);
6839 #define U64_TO_LISP_TIME(time) ltime (time)
6841 static int
6842 process_times (HANDLE h_proc, Lisp_Object *ctime, Lisp_Object *etime,
6843 Lisp_Object *stime, Lisp_Object *utime, Lisp_Object *ttime,
6844 double *pcpu)
6846 FILETIME ft_creation, ft_exit, ft_kernel, ft_user, ft_current;
6847 ULONGLONG tem1, tem2, tem3, tem;
6849 if (!h_proc
6850 || !get_process_times_fn
6851 || !(*get_process_times_fn) (h_proc, &ft_creation, &ft_exit,
6852 &ft_kernel, &ft_user))
6853 return 0;
6855 GetSystemTimeAsFileTime (&ft_current);
6857 FILETIME_TO_U64 (tem1, ft_kernel);
6858 *stime = U64_TO_LISP_TIME (tem1);
6860 FILETIME_TO_U64 (tem2, ft_user);
6861 *utime = U64_TO_LISP_TIME (tem2);
6863 tem3 = tem1 + tem2;
6864 *ttime = U64_TO_LISP_TIME (tem3);
6866 FILETIME_TO_U64 (tem, ft_creation);
6867 /* Process no 4 (System) returns zero creation time. */
6868 if (tem)
6869 tem -= utc_base;
6870 *ctime = U64_TO_LISP_TIME (tem);
6872 if (tem)
6874 FILETIME_TO_U64 (tem3, ft_current);
6875 tem = (tem3 - utc_base) - tem;
6877 *etime = U64_TO_LISP_TIME (tem);
6879 if (tem)
6881 *pcpu = 100.0 * (tem1 + tem2) / tem;
6882 if (*pcpu > 100)
6883 *pcpu = 100.0;
6885 else
6886 *pcpu = 0;
6888 return 1;
6891 Lisp_Object
6892 system_process_attributes (Lisp_Object pid)
6894 Lisp_Object attrs = Qnil;
6895 Lisp_Object cmd_str, decoded_cmd, tem;
6896 HANDLE h_snapshot, h_proc;
6897 DWORD proc_id;
6898 int found_proc = 0;
6899 char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
6900 DWORD ulength = sizeof (uname), dlength = sizeof (domain), needed;
6901 DWORD glength = sizeof (gname);
6902 HANDLE token = NULL;
6903 SID_NAME_USE user_type;
6904 unsigned char *buf = NULL;
6905 DWORD blen = 0;
6906 TOKEN_USER user_token;
6907 TOKEN_PRIMARY_GROUP group_token;
6908 unsigned euid;
6909 unsigned egid;
6910 PROCESS_MEMORY_COUNTERS mem;
6911 PROCESS_MEMORY_COUNTERS_EX mem_ex;
6912 SIZE_T minrss, maxrss;
6913 MEMORYSTATUS memst;
6914 MEMORY_STATUS_EX memstex;
6915 double totphys = 0.0;
6916 Lisp_Object ctime, stime, utime, etime, ttime;
6917 double pcpu;
6918 BOOL result = FALSE;
6920 CHECK_NUMBER_OR_FLOAT (pid);
6921 proc_id = FLOATP (pid) ? XFLOAT_DATA (pid) : XINT (pid);
6923 h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
6925 if (h_snapshot != INVALID_HANDLE_VALUE)
6927 PROCESSENTRY32 pe;
6928 BOOL res;
6930 pe.dwSize = sizeof (PROCESSENTRY32);
6931 for (res = process32_first (h_snapshot, &pe); res;
6932 res = process32_next (h_snapshot, &pe))
6934 if (proc_id == pe.th32ProcessID)
6936 if (proc_id == 0)
6937 decoded_cmd = build_string ("Idle");
6938 else
6940 /* Decode the command name from locale-specific
6941 encoding. */
6942 cmd_str = build_unibyte_string (pe.szExeFile);
6944 decoded_cmd =
6945 code_convert_string_norecord (cmd_str,
6946 Vlocale_coding_system, 0);
6948 attrs = Fcons (Fcons (Qcomm, decoded_cmd), attrs);
6949 attrs = Fcons (Fcons (Qppid,
6950 make_fixnum_or_float (pe.th32ParentProcessID)),
6951 attrs);
6952 attrs = Fcons (Fcons (Qpri, make_number (pe.pcPriClassBase)),
6953 attrs);
6954 attrs = Fcons (Fcons (Qthcount,
6955 make_fixnum_or_float (pe.cntThreads)),
6956 attrs);
6957 found_proc = 1;
6958 break;
6962 CloseHandle (h_snapshot);
6965 if (!found_proc)
6966 return Qnil;
6968 h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
6969 FALSE, proc_id);
6970 /* If we were denied a handle to the process, try again after
6971 enabling the SeDebugPrivilege in our process. */
6972 if (!h_proc)
6974 TOKEN_PRIVILEGES priv_current;
6976 if (enable_privilege (SE_DEBUG_NAME, TRUE, &priv_current))
6978 h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
6979 FALSE, proc_id);
6980 restore_privilege (&priv_current);
6981 revert_to_self ();
6984 if (h_proc)
6986 result = open_process_token (h_proc, TOKEN_QUERY, &token);
6987 if (result)
6989 result = get_token_information (token, TokenUser, NULL, 0, &blen);
6990 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
6992 buf = xmalloc (blen);
6993 result = get_token_information (token, TokenUser,
6994 (LPVOID)buf, blen, &needed);
6995 if (result)
6997 memcpy (&user_token, buf, sizeof (user_token));
6998 if (!w32_cached_id (user_token.User.Sid, &euid, uname))
7000 euid = get_rid (user_token.User.Sid);
7001 result = lookup_account_sid (NULL, user_token.User.Sid,
7002 uname, &ulength,
7003 domain, &dlength,
7004 &user_type);
7005 if (result)
7006 w32_add_to_cache (user_token.User.Sid, euid, uname);
7007 else
7009 strcpy (uname, "unknown");
7010 result = TRUE;
7013 ulength = strlen (uname);
7017 if (result)
7019 /* Determine a reasonable euid and gid values. */
7020 if (xstrcasecmp ("administrator", uname) == 0)
7022 euid = 500; /* well-known Administrator uid */
7023 egid = 513; /* well-known None gid */
7025 else
7027 /* Get group id and name. */
7028 result = get_token_information (token, TokenPrimaryGroup,
7029 (LPVOID)buf, blen, &needed);
7030 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
7032 buf = xrealloc (buf, blen = needed);
7033 result = get_token_information (token, TokenPrimaryGroup,
7034 (LPVOID)buf, blen, &needed);
7036 if (result)
7038 memcpy (&group_token, buf, sizeof (group_token));
7039 if (!w32_cached_id (group_token.PrimaryGroup, &egid, gname))
7041 egid = get_rid (group_token.PrimaryGroup);
7042 dlength = sizeof (domain);
7043 result =
7044 lookup_account_sid (NULL, group_token.PrimaryGroup,
7045 gname, &glength, NULL, &dlength,
7046 &user_type);
7047 if (result)
7048 w32_add_to_cache (group_token.PrimaryGroup,
7049 egid, gname);
7050 else
7052 strcpy (gname, "None");
7053 result = TRUE;
7056 glength = strlen (gname);
7060 xfree (buf);
7062 if (!result)
7064 if (!is_windows_9x ())
7066 /* We couldn't open the process token, presumably because of
7067 insufficient access rights. Assume this process is run
7068 by the system. */
7069 strcpy (uname, "SYSTEM");
7070 strcpy (gname, "None");
7071 euid = 18; /* SYSTEM */
7072 egid = 513; /* None */
7073 glength = strlen (gname);
7074 ulength = strlen (uname);
7076 /* If we are running under Windows 9X, where security calls are
7077 not supported, we assume all processes are run by the current
7078 user. */
7079 else if (GetUserName (uname, &ulength))
7081 if (xstrcasecmp ("administrator", uname) == 0)
7082 euid = 0;
7083 else
7084 euid = 123;
7085 egid = euid;
7086 strcpy (gname, "None");
7087 glength = strlen (gname);
7088 ulength = strlen (uname);
7090 else
7092 euid = 123;
7093 egid = 123;
7094 strcpy (uname, "administrator");
7095 ulength = strlen (uname);
7096 strcpy (gname, "None");
7097 glength = strlen (gname);
7099 if (token)
7100 CloseHandle (token);
7103 attrs = Fcons (Fcons (Qeuid, make_fixnum_or_float (euid)), attrs);
7104 tem = make_unibyte_string (uname, ulength);
7105 attrs = Fcons (Fcons (Quser,
7106 code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
7107 attrs);
7108 attrs = Fcons (Fcons (Qegid, make_fixnum_or_float (egid)), attrs);
7109 tem = make_unibyte_string (gname, glength);
7110 attrs = Fcons (Fcons (Qgroup,
7111 code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
7112 attrs);
7114 if (global_memory_status_ex (&memstex))
7115 #if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
7116 totphys = memstex.ullTotalPhys / 1024.0;
7117 #else
7118 /* Visual Studio 6 cannot convert an unsigned __int64 type to
7119 double, so we need to do this for it... */
7121 DWORD tot_hi = memstex.ullTotalPhys >> 32;
7122 DWORD tot_md = (memstex.ullTotalPhys & 0x00000000ffffffff) >> 10;
7123 DWORD tot_lo = memstex.ullTotalPhys % 1024;
7125 totphys = tot_hi * 4194304.0 + tot_md + tot_lo / 1024.0;
7127 #endif /* __GNUC__ || _MSC_VER >= 1300 */
7128 else if (global_memory_status (&memst))
7129 totphys = memst.dwTotalPhys / 1024.0;
7131 if (h_proc
7132 && get_process_memory_info (h_proc, (PROCESS_MEMORY_COUNTERS *)&mem_ex,
7133 sizeof (mem_ex)))
7135 SIZE_T rss = mem_ex.WorkingSetSize / 1024;
7137 attrs = Fcons (Fcons (Qmajflt,
7138 make_fixnum_or_float (mem_ex.PageFaultCount)),
7139 attrs);
7140 attrs = Fcons (Fcons (Qvsize,
7141 make_fixnum_or_float (mem_ex.PrivateUsage / 1024)),
7142 attrs);
7143 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (rss)), attrs);
7144 if (totphys)
7145 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
7147 else if (h_proc
7148 && get_process_memory_info (h_proc, &mem, sizeof (mem)))
7150 SIZE_T rss = mem_ex.WorkingSetSize / 1024;
7152 attrs = Fcons (Fcons (Qmajflt,
7153 make_fixnum_or_float (mem.PageFaultCount)),
7154 attrs);
7155 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (rss)), attrs);
7156 if (totphys)
7157 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
7159 else if (h_proc
7160 && get_process_working_set_size (h_proc, &minrss, &maxrss))
7162 DWORD rss = maxrss / 1024;
7164 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (maxrss / 1024)), attrs);
7165 if (totphys)
7166 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
7169 if (process_times (h_proc, &ctime, &etime, &stime, &utime, &ttime, &pcpu))
7171 attrs = Fcons (Fcons (Qutime, utime), attrs);
7172 attrs = Fcons (Fcons (Qstime, stime), attrs);
7173 attrs = Fcons (Fcons (Qtime, ttime), attrs);
7174 attrs = Fcons (Fcons (Qstart, ctime), attrs);
7175 attrs = Fcons (Fcons (Qetime, etime), attrs);
7176 attrs = Fcons (Fcons (Qpcpu, make_float (pcpu)), attrs);
7179 /* FIXME: Retrieve command line by walking the PEB of the process. */
7181 if (h_proc)
7182 CloseHandle (h_proc);
7183 return attrs;
7187 w32_memory_info (unsigned long long *totalram, unsigned long long *freeram,
7188 unsigned long long *totalswap, unsigned long long *freeswap)
7190 MEMORYSTATUS memst;
7191 MEMORY_STATUS_EX memstex;
7193 /* Use GlobalMemoryStatusEx if available, as it can report more than
7194 2GB of memory. */
7195 if (global_memory_status_ex (&memstex))
7197 *totalram = memstex.ullTotalPhys;
7198 *freeram = memstex.ullAvailPhys;
7199 *totalswap = memstex.ullTotalPageFile;
7200 *freeswap = memstex.ullAvailPageFile;
7201 return 0;
7203 else if (global_memory_status (&memst))
7205 *totalram = memst.dwTotalPhys;
7206 *freeram = memst.dwAvailPhys;
7207 *totalswap = memst.dwTotalPageFile;
7208 *freeswap = memst.dwAvailPageFile;
7209 return 0;
7211 else
7212 return -1;
7216 /* Wrappers for winsock functions to map between our file descriptors
7217 and winsock's handles; also set h_errno for convenience.
7219 To allow Emacs to run on systems which don't have winsock support
7220 installed, we dynamically link to winsock on startup if present, and
7221 otherwise provide the minimum necessary functionality
7222 (eg. gethostname). */
7224 /* function pointers for relevant socket functions */
7225 int (PASCAL *pfn_WSAStartup) (WORD wVersionRequired, LPWSADATA lpWSAData);
7226 void (PASCAL *pfn_WSASetLastError) (int iError);
7227 int (PASCAL *pfn_WSAGetLastError) (void);
7228 int (PASCAL *pfn_WSAEventSelect) (SOCKET s, HANDLE hEventObject, long lNetworkEvents);
7229 int (PASCAL *pfn_WSAEnumNetworkEvents) (SOCKET s, HANDLE hEventObject,
7230 WSANETWORKEVENTS *NetworkEvents);
7232 HANDLE (PASCAL *pfn_WSACreateEvent) (void);
7233 int (PASCAL *pfn_WSACloseEvent) (HANDLE hEvent);
7234 int (PASCAL *pfn_socket) (int af, int type, int protocol);
7235 int (PASCAL *pfn_bind) (SOCKET s, const struct sockaddr *addr, int namelen);
7236 int (PASCAL *pfn_connect) (SOCKET s, const struct sockaddr *addr, int namelen);
7237 int (PASCAL *pfn_ioctlsocket) (SOCKET s, long cmd, u_long *argp);
7238 int (PASCAL *pfn_recv) (SOCKET s, char * buf, int len, int flags);
7239 int (PASCAL *pfn_send) (SOCKET s, const char * buf, int len, int flags);
7240 int (PASCAL *pfn_closesocket) (SOCKET s);
7241 int (PASCAL *pfn_shutdown) (SOCKET s, int how);
7242 int (PASCAL *pfn_WSACleanup) (void);
7244 u_short (PASCAL *pfn_htons) (u_short hostshort);
7245 u_short (PASCAL *pfn_ntohs) (u_short netshort);
7246 unsigned long (PASCAL *pfn_inet_addr) (const char * cp);
7247 int (PASCAL *pfn_gethostname) (char * name, int namelen);
7248 struct hostent * (PASCAL *pfn_gethostbyname) (const char * name);
7249 struct servent * (PASCAL *pfn_getservbyname) (const char * name, const char * proto);
7250 int (PASCAL *pfn_getpeername) (SOCKET s, struct sockaddr *addr, int * namelen);
7251 int (PASCAL *pfn_setsockopt) (SOCKET s, int level, int optname,
7252 const char * optval, int optlen);
7253 int (PASCAL *pfn_listen) (SOCKET s, int backlog);
7254 int (PASCAL *pfn_getsockname) (SOCKET s, struct sockaddr * name,
7255 int * namelen);
7256 SOCKET (PASCAL *pfn_accept) (SOCKET s, struct sockaddr * addr, int * addrlen);
7257 int (PASCAL *pfn_recvfrom) (SOCKET s, char * buf, int len, int flags,
7258 struct sockaddr * from, int * fromlen);
7259 int (PASCAL *pfn_sendto) (SOCKET s, const char * buf, int len, int flags,
7260 const struct sockaddr * to, int tolen);
7262 int (PASCAL *pfn_getaddrinfo) (const char *, const char *,
7263 const struct addrinfo *, struct addrinfo **);
7264 void (PASCAL *pfn_freeaddrinfo) (struct addrinfo *);
7266 /* SetHandleInformation is only needed to make sockets non-inheritable. */
7267 BOOL (WINAPI *pfn_SetHandleInformation) (HANDLE object, DWORD mask, DWORD flags);
7268 #ifndef HANDLE_FLAG_INHERIT
7269 #define HANDLE_FLAG_INHERIT 1
7270 #endif
7272 HANDLE winsock_lib;
7273 static int winsock_inuse;
7275 BOOL term_winsock (void);
7277 BOOL
7278 term_winsock (void)
7280 if (winsock_lib != NULL && winsock_inuse == 0)
7282 release_listen_threads ();
7283 /* Not sure what would cause WSAENETDOWN, or even if it can happen
7284 after WSAStartup returns successfully, but it seems reasonable
7285 to allow unloading winsock anyway in that case. */
7286 if (pfn_WSACleanup () == 0 ||
7287 pfn_WSAGetLastError () == WSAENETDOWN)
7289 if (FreeLibrary (winsock_lib))
7290 winsock_lib = NULL;
7291 return TRUE;
7294 return FALSE;
7297 BOOL
7298 init_winsock (int load_now)
7300 WSADATA winsockData;
7302 if (winsock_lib != NULL)
7303 return TRUE;
7305 pfn_SetHandleInformation
7306 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
7307 "SetHandleInformation");
7309 winsock_lib = LoadLibrary ("Ws2_32.dll");
7311 if (winsock_lib != NULL)
7313 /* dynamically link to socket functions */
7315 #define LOAD_PROC(fn) \
7316 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
7317 goto fail;
7319 LOAD_PROC (WSAStartup);
7320 LOAD_PROC (WSASetLastError);
7321 LOAD_PROC (WSAGetLastError);
7322 LOAD_PROC (WSAEventSelect);
7323 LOAD_PROC (WSAEnumNetworkEvents);
7324 LOAD_PROC (WSACreateEvent);
7325 LOAD_PROC (WSACloseEvent);
7326 LOAD_PROC (socket);
7327 LOAD_PROC (bind);
7328 LOAD_PROC (connect);
7329 LOAD_PROC (ioctlsocket);
7330 LOAD_PROC (recv);
7331 LOAD_PROC (send);
7332 LOAD_PROC (closesocket);
7333 LOAD_PROC (shutdown);
7334 LOAD_PROC (htons);
7335 LOAD_PROC (ntohs);
7336 LOAD_PROC (inet_addr);
7337 LOAD_PROC (gethostname);
7338 LOAD_PROC (gethostbyname);
7339 LOAD_PROC (getservbyname);
7340 LOAD_PROC (getpeername);
7341 LOAD_PROC (WSACleanup);
7342 LOAD_PROC (setsockopt);
7343 LOAD_PROC (listen);
7344 LOAD_PROC (getsockname);
7345 LOAD_PROC (accept);
7346 LOAD_PROC (recvfrom);
7347 LOAD_PROC (sendto);
7348 #undef LOAD_PROC
7350 /* Try loading functions not available before XP. */
7351 pfn_getaddrinfo = (void *) GetProcAddress (winsock_lib, "getaddrinfo");
7352 pfn_freeaddrinfo = (void *) GetProcAddress (winsock_lib, "freeaddrinfo");
7353 /* Paranoia: these two functions should go together, so if one
7354 is absent, we cannot use the other. */
7355 if (pfn_getaddrinfo == NULL)
7356 pfn_freeaddrinfo = NULL;
7357 else if (pfn_freeaddrinfo == NULL)
7358 pfn_getaddrinfo = NULL;
7360 /* specify version 1.1 of winsock */
7361 if (pfn_WSAStartup (0x101, &winsockData) == 0)
7363 if (winsockData.wVersion != 0x101)
7364 goto fail;
7366 if (!load_now)
7368 /* Report that winsock exists and is usable, but leave
7369 socket functions disabled. I am assuming that calling
7370 WSAStartup does not require any network interaction,
7371 and in particular does not cause or require a dial-up
7372 connection to be established. */
7374 pfn_WSACleanup ();
7375 FreeLibrary (winsock_lib);
7376 winsock_lib = NULL;
7378 winsock_inuse = 0;
7379 return TRUE;
7382 fail:
7383 FreeLibrary (winsock_lib);
7384 winsock_lib = NULL;
7387 return FALSE;
7391 int h_errno = 0;
7393 /* Function to map winsock error codes to errno codes for those errno
7394 code defined in errno.h (errno values not defined by errno.h are
7395 already in nt/inc/sys/socket.h). */
7396 static void
7397 set_errno (void)
7399 int wsa_err;
7401 h_errno = 0;
7402 if (winsock_lib == NULL)
7403 wsa_err = EINVAL;
7404 else
7405 wsa_err = pfn_WSAGetLastError ();
7407 switch (wsa_err)
7409 case WSAEACCES: errno = EACCES; break;
7410 case WSAEBADF: errno = EBADF; break;
7411 case WSAEFAULT: errno = EFAULT; break;
7412 case WSAEINTR: errno = EINTR; break;
7413 case WSAEINVAL: errno = EINVAL; break;
7414 case WSAEMFILE: errno = EMFILE; break;
7415 case WSAENAMETOOLONG: errno = ENAMETOOLONG; break;
7416 case WSAENOTEMPTY: errno = ENOTEMPTY; break;
7417 case WSAEWOULDBLOCK: errno = EWOULDBLOCK; break;
7418 case WSAENOTCONN: errno = ENOTCONN; break;
7419 default: errno = wsa_err; break;
7423 static void
7424 check_errno (void)
7426 h_errno = 0;
7427 if (winsock_lib != NULL)
7428 pfn_WSASetLastError (0);
7431 /* Extend strerror to handle the winsock-specific error codes. */
7432 struct {
7433 int errnum;
7434 const char * msg;
7435 } _wsa_errlist[] = {
7436 {WSAEINTR , "Interrupted function call"},
7437 {WSAEBADF , "Bad file descriptor"},
7438 {WSAEACCES , "Permission denied"},
7439 {WSAEFAULT , "Bad address"},
7440 {WSAEINVAL , "Invalid argument"},
7441 {WSAEMFILE , "Too many open files"},
7443 {WSAEWOULDBLOCK , "Resource temporarily unavailable"},
7444 {WSAEINPROGRESS , "Operation now in progress"},
7445 {WSAEALREADY , "Operation already in progress"},
7446 {WSAENOTSOCK , "Socket operation on non-socket"},
7447 {WSAEDESTADDRREQ , "Destination address required"},
7448 {WSAEMSGSIZE , "Message too long"},
7449 {WSAEPROTOTYPE , "Protocol wrong type for socket"},
7450 {WSAENOPROTOOPT , "Bad protocol option"},
7451 {WSAEPROTONOSUPPORT , "Protocol not supported"},
7452 {WSAESOCKTNOSUPPORT , "Socket type not supported"},
7453 {WSAEOPNOTSUPP , "Operation not supported"},
7454 {WSAEPFNOSUPPORT , "Protocol family not supported"},
7455 {WSAEAFNOSUPPORT , "Address family not supported by protocol family"},
7456 {WSAEADDRINUSE , "Address already in use"},
7457 {WSAEADDRNOTAVAIL , "Cannot assign requested address"},
7458 {WSAENETDOWN , "Network is down"},
7459 {WSAENETUNREACH , "Network is unreachable"},
7460 {WSAENETRESET , "Network dropped connection on reset"},
7461 {WSAECONNABORTED , "Software caused connection abort"},
7462 {WSAECONNRESET , "Connection reset by peer"},
7463 {WSAENOBUFS , "No buffer space available"},
7464 {WSAEISCONN , "Socket is already connected"},
7465 {WSAENOTCONN , "Socket is not connected"},
7466 {WSAESHUTDOWN , "Cannot send after socket shutdown"},
7467 {WSAETOOMANYREFS , "Too many references"}, /* not sure */
7468 {WSAETIMEDOUT , "Connection timed out"},
7469 {WSAECONNREFUSED , "Connection refused"},
7470 {WSAELOOP , "Network loop"}, /* not sure */
7471 {WSAENAMETOOLONG , "Name is too long"},
7472 {WSAEHOSTDOWN , "Host is down"},
7473 {WSAEHOSTUNREACH , "No route to host"},
7474 {WSAENOTEMPTY , "Buffer not empty"}, /* not sure */
7475 {WSAEPROCLIM , "Too many processes"},
7476 {WSAEUSERS , "Too many users"}, /* not sure */
7477 {WSAEDQUOT , "Double quote in host name"}, /* really not sure */
7478 {WSAESTALE , "Data is stale"}, /* not sure */
7479 {WSAEREMOTE , "Remote error"}, /* not sure */
7481 {WSASYSNOTREADY , "Network subsystem is unavailable"},
7482 {WSAVERNOTSUPPORTED , "WINSOCK.DLL version out of range"},
7483 {WSANOTINITIALISED , "Winsock not initialized successfully"},
7484 {WSAEDISCON , "Graceful shutdown in progress"},
7485 #ifdef WSAENOMORE
7486 {WSAENOMORE , "No more operations allowed"}, /* not sure */
7487 {WSAECANCELLED , "Operation cancelled"}, /* not sure */
7488 {WSAEINVALIDPROCTABLE , "Invalid procedure table from service provider"},
7489 {WSAEINVALIDPROVIDER , "Invalid service provider version number"},
7490 {WSAEPROVIDERFAILEDINIT , "Unable to initialize a service provider"},
7491 {WSASYSCALLFAILURE , "System call failure"},
7492 {WSASERVICE_NOT_FOUND , "Service not found"}, /* not sure */
7493 {WSATYPE_NOT_FOUND , "Class type not found"},
7494 {WSA_E_NO_MORE , "No more resources available"}, /* really not sure */
7495 {WSA_E_CANCELLED , "Operation already cancelled"}, /* really not sure */
7496 {WSAEREFUSED , "Operation refused"}, /* not sure */
7497 #endif
7499 {WSAHOST_NOT_FOUND , "Host not found"},
7500 {WSATRY_AGAIN , "Authoritative host not found during name lookup"},
7501 {WSANO_RECOVERY , "Non-recoverable error during name lookup"},
7502 {WSANO_DATA , "Valid name, no data record of requested type"},
7504 {-1, NULL}
7507 char *
7508 sys_strerror (int error_no)
7510 int i;
7511 static char unknown_msg[40];
7513 if (error_no >= 0 && error_no < sys_nerr)
7514 return sys_errlist[error_no];
7516 for (i = 0; _wsa_errlist[i].errnum >= 0; i++)
7517 if (_wsa_errlist[i].errnum == error_no)
7518 return (char *)_wsa_errlist[i].msg;
7520 sprintf (unknown_msg, "Unidentified error: %d", error_no);
7521 return unknown_msg;
7524 /* [andrewi 3-May-96] I've had conflicting results using both methods,
7525 but I believe the method of keeping the socket handle separate (and
7526 insuring it is not inheritable) is the correct one. */
7528 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
7530 static int socket_to_fd (SOCKET s);
7533 sys_socket (int af, int type, int protocol)
7535 SOCKET s;
7537 if (winsock_lib == NULL)
7539 errno = ENETDOWN;
7540 return -1;
7543 check_errno ();
7545 /* call the real socket function */
7546 s = pfn_socket (af, type, protocol);
7548 if (s != INVALID_SOCKET)
7549 return socket_to_fd (s);
7551 set_errno ();
7552 return -1;
7555 /* Convert a SOCKET to a file descriptor. */
7556 static int
7557 socket_to_fd (SOCKET s)
7559 int fd;
7560 child_process * cp;
7562 /* Although under NT 3.5 _open_osfhandle will accept a socket
7563 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
7564 that does not work under NT 3.1. However, we can get the same
7565 effect by using a backdoor function to replace an existing
7566 descriptor handle with the one we want. */
7568 /* allocate a file descriptor (with appropriate flags) */
7569 fd = _open ("NUL:", _O_RDWR);
7570 if (fd >= 0)
7572 /* Make a non-inheritable copy of the socket handle. Note
7573 that it is possible that sockets aren't actually kernel
7574 handles, which appears to be the case on Windows 9x when
7575 the MS Proxy winsock client is installed. */
7577 /* Apparently there is a bug in NT 3.51 with some service
7578 packs, which prevents using DuplicateHandle to make a
7579 socket handle non-inheritable (causes WSACleanup to
7580 hang). The work-around is to use SetHandleInformation
7581 instead if it is available and implemented. */
7582 if (pfn_SetHandleInformation)
7584 pfn_SetHandleInformation ((HANDLE) s, HANDLE_FLAG_INHERIT, 0);
7586 else
7588 HANDLE parent = GetCurrentProcess ();
7589 HANDLE new_s = INVALID_HANDLE_VALUE;
7591 if (DuplicateHandle (parent,
7592 (HANDLE) s,
7593 parent,
7594 &new_s,
7596 FALSE,
7597 DUPLICATE_SAME_ACCESS))
7599 /* It is possible that DuplicateHandle succeeds even
7600 though the socket wasn't really a kernel handle,
7601 because a real handle has the same value. So
7602 test whether the new handle really is a socket. */
7603 unsigned long nonblocking = 0;
7604 if (pfn_ioctlsocket ((SOCKET) new_s, FIONBIO, &nonblocking) == 0)
7606 pfn_closesocket (s);
7607 s = (SOCKET) new_s;
7609 else
7611 CloseHandle (new_s);
7616 eassert (fd < MAXDESC);
7617 fd_info[fd].hnd = (HANDLE) s;
7619 /* set our own internal flags */
7620 fd_info[fd].flags = FILE_SOCKET | FILE_BINARY | FILE_READ | FILE_WRITE;
7622 cp = new_child ();
7623 if (cp)
7625 cp->fd = fd;
7626 cp->status = STATUS_READ_ACKNOWLEDGED;
7628 /* attach child_process to fd_info */
7629 if (fd_info[ fd ].cp != NULL)
7631 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd));
7632 emacs_abort ();
7635 fd_info[ fd ].cp = cp;
7637 /* success! */
7638 winsock_inuse++; /* count open sockets */
7639 return fd;
7642 /* clean up */
7643 _close (fd);
7645 else
7646 pfn_closesocket (s);
7647 errno = EMFILE;
7648 return -1;
7652 sys_bind (int s, const struct sockaddr * addr, int namelen)
7654 if (winsock_lib == NULL)
7656 errno = ENOTSOCK;
7657 return SOCKET_ERROR;
7660 check_errno ();
7661 if (fd_info[s].flags & FILE_SOCKET)
7663 int rc = pfn_bind (SOCK_HANDLE (s), addr, namelen);
7664 if (rc == SOCKET_ERROR)
7665 set_errno ();
7666 return rc;
7668 errno = ENOTSOCK;
7669 return SOCKET_ERROR;
7673 sys_connect (int s, const struct sockaddr * name, int namelen)
7675 if (winsock_lib == NULL)
7677 errno = ENOTSOCK;
7678 return SOCKET_ERROR;
7681 check_errno ();
7682 if (fd_info[s].flags & FILE_SOCKET)
7684 int rc = pfn_connect (SOCK_HANDLE (s), name, namelen);
7685 if (rc == SOCKET_ERROR)
7687 set_errno ();
7688 /* If this is a non-blocking 'connect', set the bit in flags
7689 that will tell reader_thread to wait for connection
7690 before trying to read. */
7691 if (errno == EWOULDBLOCK && (fd_info[s].flags & FILE_NDELAY) != 0)
7693 errno = EINPROGRESS; /* that's what process.c expects */
7694 fd_info[s].flags |= FILE_CONNECT;
7697 return rc;
7699 errno = ENOTSOCK;
7700 return SOCKET_ERROR;
7703 u_short
7704 sys_htons (u_short hostshort)
7706 return (winsock_lib != NULL) ?
7707 pfn_htons (hostshort) : hostshort;
7710 u_short
7711 sys_ntohs (u_short netshort)
7713 return (winsock_lib != NULL) ?
7714 pfn_ntohs (netshort) : netshort;
7717 unsigned long
7718 sys_inet_addr (const char * cp)
7720 return (winsock_lib != NULL) ?
7721 pfn_inet_addr (cp) : INADDR_NONE;
7725 sys_gethostname (char * name, int namelen)
7727 if (winsock_lib != NULL)
7729 int retval;
7731 check_errno ();
7732 retval = pfn_gethostname (name, namelen);
7733 if (retval == SOCKET_ERROR)
7734 set_errno ();
7735 return retval;
7738 if (namelen > MAX_COMPUTERNAME_LENGTH)
7739 return !GetComputerName (name, (DWORD *)&namelen);
7741 errno = EFAULT;
7742 return SOCKET_ERROR;
7745 struct hostent *
7746 sys_gethostbyname (const char * name)
7748 struct hostent * host;
7749 int h_err = h_errno;
7751 if (winsock_lib == NULL)
7753 h_errno = NO_RECOVERY;
7754 errno = ENETDOWN;
7755 return NULL;
7758 check_errno ();
7759 host = pfn_gethostbyname (name);
7760 if (!host)
7762 set_errno ();
7763 h_errno = errno;
7765 else
7766 h_errno = h_err;
7767 return host;
7770 struct servent *
7771 sys_getservbyname (const char * name, const char * proto)
7773 struct servent * serv;
7775 if (winsock_lib == NULL)
7777 errno = ENETDOWN;
7778 return NULL;
7781 check_errno ();
7782 serv = pfn_getservbyname (name, proto);
7783 if (!serv)
7784 set_errno ();
7785 return serv;
7789 sys_getpeername (int s, struct sockaddr *addr, int * namelen)
7791 if (winsock_lib == NULL)
7793 errno = ENETDOWN;
7794 return SOCKET_ERROR;
7797 check_errno ();
7798 if (fd_info[s].flags & FILE_SOCKET)
7800 int rc = pfn_getpeername (SOCK_HANDLE (s), addr, namelen);
7801 if (rc == SOCKET_ERROR)
7802 set_errno ();
7803 return rc;
7805 errno = ENOTSOCK;
7806 return SOCKET_ERROR;
7810 sys_getaddrinfo (const char *node, const char *service,
7811 const struct addrinfo *hints, struct addrinfo **res)
7813 int rc;
7815 if (winsock_lib == NULL)
7817 errno = ENETDOWN;
7818 return SOCKET_ERROR;
7821 check_errno ();
7822 if (pfn_getaddrinfo)
7823 rc = pfn_getaddrinfo (node, service, hints, res);
7824 else
7826 int port = 0;
7827 struct hostent *host_info;
7828 struct gai_storage {
7829 struct addrinfo addrinfo;
7830 struct sockaddr_in sockaddr_in;
7831 } *gai_storage;
7833 /* We don't (yet) support any flags, as Emacs doesn't need that. */
7834 if (hints && hints->ai_flags != 0)
7835 return WSAEINVAL;
7836 /* NODE cannot be NULL, since process.c has fallbacks for that. */
7837 if (!node)
7838 return WSAHOST_NOT_FOUND;
7840 if (service)
7842 const char *protocol =
7843 (hints && hints->ai_socktype == SOCK_DGRAM) ? "udp" : "tcp";
7844 struct servent *srv = sys_getservbyname (service, protocol);
7846 if (srv)
7847 port = srv->s_port;
7848 else if (*service >= '0' && *service <= '9')
7850 char *endp;
7852 port = strtoul (service, &endp, 10);
7853 if (*endp || port > 65536)
7854 return WSAHOST_NOT_FOUND;
7855 port = sys_htons ((unsigned short) port);
7857 else
7858 return WSAHOST_NOT_FOUND;
7861 gai_storage = xzalloc (sizeof *gai_storage);
7862 gai_storage->sockaddr_in.sin_port = port;
7863 host_info = sys_gethostbyname (node);
7864 if (host_info)
7866 memcpy (&gai_storage->sockaddr_in.sin_addr,
7867 host_info->h_addr, host_info->h_length);
7868 gai_storage->sockaddr_in.sin_family = host_info->h_addrtype;
7870 else
7872 /* Attempt to interpret host as numeric inet address. */
7873 unsigned long numeric_addr = sys_inet_addr (node);
7875 if (numeric_addr == -1)
7877 free (gai_storage);
7878 return WSAHOST_NOT_FOUND;
7881 memcpy (&gai_storage->sockaddr_in.sin_addr, &numeric_addr,
7882 sizeof (gai_storage->sockaddr_in.sin_addr));
7883 gai_storage->sockaddr_in.sin_family = (hints) ? hints->ai_family : 0;
7886 gai_storage->addrinfo.ai_addr =
7887 (struct sockaddr *)&gai_storage->sockaddr_in;
7888 gai_storage->addrinfo.ai_addrlen = sizeof (gai_storage->sockaddr_in);
7889 gai_storage->addrinfo.ai_protocol = (hints) ? hints->ai_protocol : 0;
7890 gai_storage->addrinfo.ai_socktype = (hints) ? hints->ai_socktype : 0;
7891 gai_storage->addrinfo.ai_family = gai_storage->sockaddr_in.sin_family;
7892 gai_storage->addrinfo.ai_next = NULL;
7894 *res = &gai_storage->addrinfo;
7895 rc = 0;
7898 return rc;
7901 void
7902 sys_freeaddrinfo (struct addrinfo *ai)
7904 if (winsock_lib == NULL)
7906 errno = ENETDOWN;
7907 return;
7910 check_errno ();
7911 if (pfn_freeaddrinfo)
7912 pfn_freeaddrinfo (ai);
7913 else
7915 eassert (ai->ai_next == NULL);
7916 xfree (ai);
7921 sys_shutdown (int s, int how)
7923 if (winsock_lib == NULL)
7925 errno = ENETDOWN;
7926 return SOCKET_ERROR;
7929 check_errno ();
7930 if (fd_info[s].flags & FILE_SOCKET)
7932 int rc = pfn_shutdown (SOCK_HANDLE (s), how);
7933 if (rc == SOCKET_ERROR)
7934 set_errno ();
7935 return rc;
7937 errno = ENOTSOCK;
7938 return SOCKET_ERROR;
7942 sys_setsockopt (int s, int level, int optname, const void * optval, int optlen)
7944 if (winsock_lib == NULL)
7946 errno = ENETDOWN;
7947 return SOCKET_ERROR;
7950 check_errno ();
7951 if (fd_info[s].flags & FILE_SOCKET)
7953 int rc = pfn_setsockopt (SOCK_HANDLE (s), level, optname,
7954 (const char *)optval, optlen);
7955 if (rc == SOCKET_ERROR)
7956 set_errno ();
7957 return rc;
7959 errno = ENOTSOCK;
7960 return SOCKET_ERROR;
7964 sys_listen (int s, int backlog)
7966 if (winsock_lib == NULL)
7968 errno = ENETDOWN;
7969 return SOCKET_ERROR;
7972 check_errno ();
7973 if (fd_info[s].flags & FILE_SOCKET)
7975 int rc = pfn_listen (SOCK_HANDLE (s), backlog);
7976 if (rc == SOCKET_ERROR)
7977 set_errno ();
7978 else
7979 fd_info[s].flags |= FILE_LISTEN;
7980 return rc;
7982 errno = ENOTSOCK;
7983 return SOCKET_ERROR;
7987 sys_getsockname (int s, struct sockaddr * name, int * namelen)
7989 if (winsock_lib == NULL)
7991 errno = ENETDOWN;
7992 return SOCKET_ERROR;
7995 check_errno ();
7996 if (fd_info[s].flags & FILE_SOCKET)
7998 int rc = pfn_getsockname (SOCK_HANDLE (s), name, namelen);
7999 if (rc == SOCKET_ERROR)
8000 set_errno ();
8001 return rc;
8003 errno = ENOTSOCK;
8004 return SOCKET_ERROR;
8008 sys_accept (int s, struct sockaddr * addr, int * addrlen)
8010 if (winsock_lib == NULL)
8012 errno = ENETDOWN;
8013 return -1;
8016 check_errno ();
8017 if (fd_info[s].flags & FILE_LISTEN)
8019 SOCKET t = pfn_accept (SOCK_HANDLE (s), addr, addrlen);
8020 int fd = -1;
8021 if (t == INVALID_SOCKET)
8022 set_errno ();
8023 else
8024 fd = socket_to_fd (t);
8026 if (fd >= 0)
8028 fd_info[s].cp->status = STATUS_READ_ACKNOWLEDGED;
8029 ResetEvent (fd_info[s].cp->char_avail);
8031 return fd;
8033 errno = ENOTSOCK;
8034 return -1;
8038 sys_recvfrom (int s, char * buf, int len, int flags,
8039 struct sockaddr * from, int * fromlen)
8041 if (winsock_lib == NULL)
8043 errno = ENETDOWN;
8044 return SOCKET_ERROR;
8047 check_errno ();
8048 if (fd_info[s].flags & FILE_SOCKET)
8050 int rc = pfn_recvfrom (SOCK_HANDLE (s), buf, len, flags, from, fromlen);
8051 if (rc == SOCKET_ERROR)
8052 set_errno ();
8053 return rc;
8055 errno = ENOTSOCK;
8056 return SOCKET_ERROR;
8060 sys_sendto (int s, const char * buf, int len, int flags,
8061 const struct sockaddr * to, int tolen)
8063 if (winsock_lib == NULL)
8065 errno = ENETDOWN;
8066 return SOCKET_ERROR;
8069 check_errno ();
8070 if (fd_info[s].flags & FILE_SOCKET)
8072 int rc = pfn_sendto (SOCK_HANDLE (s), buf, len, flags, to, tolen);
8073 if (rc == SOCKET_ERROR)
8074 set_errno ();
8075 return rc;
8077 errno = ENOTSOCK;
8078 return SOCKET_ERROR;
8081 /* Windows does not have an fcntl function. Provide an implementation
8082 good enough for Emacs. */
8084 fcntl (int s, int cmd, int options)
8086 /* In the w32 Emacs port, fcntl (fd, F_DUPFD_CLOEXEC, fd1) is always
8087 invoked in a context where fd1 is closed and all descriptors less
8088 than fd1 are open, so sys_dup is an adequate implementation. */
8089 if (cmd == F_DUPFD_CLOEXEC)
8090 return sys_dup (s);
8092 check_errno ();
8093 if (fd_info[s].flags & FILE_SOCKET)
8095 if (winsock_lib == NULL)
8097 errno = ENETDOWN;
8098 return -1;
8101 if (cmd == F_SETFL && options == O_NONBLOCK)
8103 unsigned long nblock = 1;
8104 int rc = pfn_ioctlsocket (SOCK_HANDLE (s), FIONBIO, &nblock);
8105 if (rc == SOCKET_ERROR)
8106 set_errno ();
8107 /* Keep track of the fact that we set this to non-blocking. */
8108 fd_info[s].flags |= FILE_NDELAY;
8109 return rc;
8111 else
8113 errno = EINVAL;
8114 return SOCKET_ERROR;
8117 else if ((fd_info[s].flags & (FILE_PIPE | FILE_WRITE))
8118 == (FILE_PIPE | FILE_WRITE))
8120 /* Force our writes to pipes be non-blocking. */
8121 if (cmd == F_SETFL && options == O_NONBLOCK)
8123 HANDLE h = (HANDLE)_get_osfhandle (s);
8124 DWORD pipe_mode = PIPE_NOWAIT;
8126 if (!SetNamedPipeHandleState (h, &pipe_mode, NULL, NULL))
8128 DebPrint (("SetNamedPipeHandleState: %lu\n", GetLastError ()));
8129 return SOCKET_ERROR;
8131 fd_info[s].flags |= FILE_NDELAY;
8132 return 0;
8134 else
8136 errno = EINVAL;
8137 return SOCKET_ERROR;
8140 errno = ENOTSOCK;
8141 return SOCKET_ERROR;
8145 /* Shadow main io functions: we need to handle pipes and sockets more
8146 intelligently. */
8149 sys_close (int fd)
8151 int rc;
8153 if (fd < 0)
8155 errno = EBADF;
8156 return -1;
8159 if (fd < MAXDESC && fd_info[fd].cp)
8161 child_process * cp = fd_info[fd].cp;
8163 fd_info[fd].cp = NULL;
8165 if (CHILD_ACTIVE (cp))
8167 /* if last descriptor to active child_process then cleanup */
8168 int i;
8169 for (i = 0; i < MAXDESC; i++)
8171 if (i == fd)
8172 continue;
8173 if (fd_info[i].cp == cp)
8174 break;
8176 if (i == MAXDESC)
8178 if (fd_info[fd].flags & FILE_SOCKET)
8180 if (winsock_lib == NULL) emacs_abort ();
8182 pfn_shutdown (SOCK_HANDLE (fd), 2);
8183 rc = pfn_closesocket (SOCK_HANDLE (fd));
8185 winsock_inuse--; /* count open sockets */
8187 /* If the process handle is NULL, it's either a socket
8188 or serial connection, or a subprocess that was
8189 already reaped by reap_subprocess, but whose
8190 resources were not yet freed, because its output was
8191 not fully read yet by the time it was reaped. (This
8192 usually happens with async subprocesses whose output
8193 is being read by Emacs.) Otherwise, this process was
8194 not reaped yet, so we set its FD to a negative value
8195 to make sure sys_select will eventually get to
8196 calling the SIGCHLD handler for it, which will then
8197 invoke waitpid and reap_subprocess. */
8198 if (cp->procinfo.hProcess == NULL)
8199 delete_child (cp);
8200 else
8201 cp->fd = -1;
8206 if (fd >= 0 && fd < MAXDESC)
8207 fd_info[fd].flags = 0;
8209 /* Note that sockets do not need special treatment here (at least on
8210 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
8211 closesocket is equivalent to CloseHandle, which is to be expected
8212 because socket handles are fully fledged kernel handles. */
8213 rc = _close (fd);
8215 return rc;
8219 sys_dup (int fd)
8221 int new_fd;
8223 new_fd = _dup (fd);
8224 if (new_fd >= 0 && new_fd < MAXDESC)
8226 /* duplicate our internal info as well */
8227 fd_info[new_fd] = fd_info[fd];
8229 return new_fd;
8233 sys_dup2 (int src, int dst)
8235 int rc;
8237 if (dst < 0 || dst >= MAXDESC)
8239 errno = EBADF;
8240 return -1;
8243 /* MS _dup2 seems to have weird side effect when invoked with 2
8244 identical arguments: an attempt to fclose the corresponding stdio
8245 stream after that hangs (we do close standard streams in
8246 init_ntproc). Attempt to avoid that by not calling _dup2 that
8247 way: if SRC is valid, we know that dup2 should be a no-op, so do
8248 nothing and return DST. */
8249 if (src == dst)
8251 if ((HANDLE)_get_osfhandle (src) == INVALID_HANDLE_VALUE)
8253 errno = EBADF;
8254 return -1;
8256 return dst;
8259 /* Make sure we close the destination first if it's a pipe or socket. */
8260 if (fd_info[dst].flags != 0)
8261 sys_close (dst);
8263 rc = _dup2 (src, dst);
8264 if (rc == 0)
8266 /* Duplicate our internal info as well. */
8267 fd_info[dst] = fd_info[src];
8269 return rc == 0 ? dst : rc;
8273 pipe2 (int * phandles, int pipe2_flags)
8275 int rc;
8276 unsigned flags;
8277 unsigned pipe_size = 0;
8279 eassert (pipe2_flags == (O_BINARY | O_CLOEXEC));
8281 /* Allow Lisp to override the default buffer size of the pipe. */
8282 if (w32_pipe_buffer_size > 0 && w32_pipe_buffer_size < UINT_MAX)
8283 pipe_size = w32_pipe_buffer_size;
8285 /* make pipe handles non-inheritable; when we spawn a child, we
8286 replace the relevant handle with an inheritable one. Also put
8287 pipes into binary mode; we will do text mode translation ourselves
8288 if required. */
8289 rc = _pipe (phandles, pipe_size, _O_NOINHERIT | _O_BINARY);
8291 if (rc == 0)
8293 /* Protect against overflow, since Windows can open more handles than
8294 our fd_info array has room for. */
8295 if (phandles[0] >= MAXDESC || phandles[1] >= MAXDESC)
8297 _close (phandles[0]);
8298 _close (phandles[1]);
8299 errno = EMFILE;
8300 rc = -1;
8302 else
8304 flags = FILE_PIPE | FILE_READ | FILE_BINARY;
8305 fd_info[phandles[0]].flags = flags;
8307 flags = FILE_PIPE | FILE_WRITE | FILE_BINARY;
8308 fd_info[phandles[1]].flags = flags;
8312 return rc;
8315 /* Function to do blocking read of one byte, needed to implement
8316 select. It is only allowed on communication ports, sockets, or
8317 pipes. */
8319 _sys_read_ahead (int fd)
8321 child_process * cp;
8322 int rc;
8324 if (fd < 0 || fd >= MAXDESC)
8325 return STATUS_READ_ERROR;
8327 cp = fd_info[fd].cp;
8329 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
8330 return STATUS_READ_ERROR;
8332 if ((fd_info[fd].flags & (FILE_PIPE | FILE_SERIAL | FILE_SOCKET)) == 0
8333 || (fd_info[fd].flags & FILE_READ) == 0)
8335 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd));
8336 emacs_abort ();
8339 if ((fd_info[fd].flags & FILE_CONNECT) != 0)
8340 DebPrint (("_sys_read_ahead: read requested from fd %d, which waits for async connect!\n", fd));
8341 cp->status = STATUS_READ_IN_PROGRESS;
8343 if (fd_info[fd].flags & FILE_PIPE)
8345 rc = _read (fd, &cp->chr, sizeof (char));
8347 /* Give subprocess time to buffer some more output for us before
8348 reporting that input is available; we need this because Windows 95
8349 connects DOS programs to pipes by making the pipe appear to be
8350 the normal console stdout - as a result most DOS programs will
8351 write to stdout without buffering, ie. one character at a
8352 time. Even some W32 programs do this - "dir" in a command
8353 shell on NT is very slow if we don't do this. */
8354 if (rc > 0)
8356 int wait = w32_pipe_read_delay;
8358 if (wait > 0)
8359 Sleep (wait);
8360 else if (wait < 0)
8361 while (++wait <= 0)
8362 /* Yield remainder of our time slice, effectively giving a
8363 temporary priority boost to the child process. */
8364 Sleep (0);
8367 else if (fd_info[fd].flags & FILE_SERIAL)
8369 HANDLE hnd = fd_info[fd].hnd;
8370 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
8371 COMMTIMEOUTS ct;
8373 /* Configure timeouts for blocking read. */
8374 if (!GetCommTimeouts (hnd, &ct))
8376 cp->status = STATUS_READ_ERROR;
8377 return STATUS_READ_ERROR;
8379 ct.ReadIntervalTimeout = 0;
8380 ct.ReadTotalTimeoutMultiplier = 0;
8381 ct.ReadTotalTimeoutConstant = 0;
8382 if (!SetCommTimeouts (hnd, &ct))
8384 cp->status = STATUS_READ_ERROR;
8385 return STATUS_READ_ERROR;
8388 if (!ReadFile (hnd, &cp->chr, sizeof (char), (DWORD*) &rc, ovl))
8390 if (GetLastError () != ERROR_IO_PENDING)
8392 cp->status = STATUS_READ_ERROR;
8393 return STATUS_READ_ERROR;
8395 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
8397 cp->status = STATUS_READ_ERROR;
8398 return STATUS_READ_ERROR;
8402 else if (fd_info[fd].flags & FILE_SOCKET)
8404 unsigned long nblock = 0;
8405 /* We always want this to block, so temporarily disable NDELAY. */
8406 if (fd_info[fd].flags & FILE_NDELAY)
8407 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
8409 rc = pfn_recv (SOCK_HANDLE (fd), &cp->chr, sizeof (char), 0);
8411 if (fd_info[fd].flags & FILE_NDELAY)
8413 nblock = 1;
8414 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
8418 if (rc == sizeof (char))
8419 cp->status = STATUS_READ_SUCCEEDED;
8420 else
8421 cp->status = STATUS_READ_FAILED;
8423 return cp->status;
8427 _sys_wait_accept (int fd)
8429 HANDLE hEv;
8430 child_process * cp;
8431 int rc;
8433 if (fd < 0 || fd >= MAXDESC)
8434 return STATUS_READ_ERROR;
8436 cp = fd_info[fd].cp;
8438 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
8439 return STATUS_READ_ERROR;
8441 cp->status = STATUS_READ_FAILED;
8443 hEv = pfn_WSACreateEvent ();
8444 rc = pfn_WSAEventSelect (SOCK_HANDLE (fd), hEv, FD_ACCEPT);
8445 if (rc != SOCKET_ERROR)
8447 do {
8448 rc = WaitForSingleObject (hEv, 500);
8449 Sleep (5);
8450 } while (rc == WAIT_TIMEOUT
8451 && cp->status != STATUS_READ_ERROR
8452 && cp->char_avail);
8453 pfn_WSAEventSelect (SOCK_HANDLE (fd), NULL, 0);
8454 if (rc == WAIT_OBJECT_0)
8455 cp->status = STATUS_READ_SUCCEEDED;
8457 pfn_WSACloseEvent (hEv);
8459 return cp->status;
8463 _sys_wait_connect (int fd)
8465 HANDLE hEv;
8466 child_process * cp;
8467 int rc;
8469 if (fd < 0 || fd >= MAXDESC)
8470 return STATUS_READ_ERROR;
8472 cp = fd_info[fd].cp;
8473 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
8474 return STATUS_READ_ERROR;
8476 cp->status = STATUS_READ_FAILED;
8478 hEv = pfn_WSACreateEvent ();
8479 rc = pfn_WSAEventSelect (SOCK_HANDLE (fd), hEv, FD_CONNECT);
8480 if (rc != SOCKET_ERROR)
8482 do {
8483 rc = WaitForSingleObject (hEv, 500);
8484 Sleep (5);
8485 } while (rc == WAIT_TIMEOUT
8486 && cp->status != STATUS_READ_ERROR
8487 && cp->char_avail);
8488 if (rc == WAIT_OBJECT_0)
8490 /* We've got an event, but it could be a successful
8491 connection, or it could be a failure. Find out
8492 which one is it. */
8493 WSANETWORKEVENTS events;
8495 pfn_WSAEnumNetworkEvents (SOCK_HANDLE (fd), hEv, &events);
8496 if ((events.lNetworkEvents & FD_CONNECT) != 0
8497 && events.iErrorCode[FD_CONNECT_BIT])
8499 cp->status = STATUS_CONNECT_FAILED;
8500 cp->errcode = events.iErrorCode[FD_CONNECT_BIT];
8502 else
8504 cp->status = STATUS_READ_SUCCEEDED;
8505 cp->errcode = 0;
8508 pfn_WSAEventSelect (SOCK_HANDLE (fd), NULL, 0);
8510 else
8511 pfn_WSACloseEvent (hEv);
8513 return cp->status;
8517 sys_read (int fd, char * buffer, unsigned int count)
8519 int nchars;
8520 int to_read;
8521 DWORD waiting;
8522 char * orig_buffer = buffer;
8524 if (fd < 0)
8526 errno = EBADF;
8527 return -1;
8530 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
8532 child_process *cp = fd_info[fd].cp;
8534 if ((fd_info[fd].flags & FILE_READ) == 0)
8536 errno = EBADF;
8537 return -1;
8540 nchars = 0;
8542 /* re-read CR carried over from last read */
8543 if (fd_info[fd].flags & FILE_LAST_CR)
8545 if (fd_info[fd].flags & FILE_BINARY) emacs_abort ();
8546 *buffer++ = 0x0d;
8547 count--;
8548 nchars++;
8549 fd_info[fd].flags &= ~FILE_LAST_CR;
8552 /* presence of a child_process structure means we are operating in
8553 non-blocking mode - otherwise we just call _read directly.
8554 Note that the child_process structure might be missing because
8555 reap_subprocess has been called; in this case the pipe is
8556 already broken, so calling _read on it is okay. */
8557 if (cp)
8559 int current_status = cp->status;
8561 switch (current_status)
8563 case STATUS_READ_FAILED:
8564 case STATUS_READ_ERROR:
8565 /* report normal EOF if nothing in buffer */
8566 if (nchars <= 0)
8567 fd_info[fd].flags |= FILE_AT_EOF;
8568 return nchars;
8570 case STATUS_READ_READY:
8571 case STATUS_READ_IN_PROGRESS:
8572 #if 0
8573 /* This happens all the time during GnuTLS handshake
8574 with the remote, evidently because GnuTLS waits for
8575 the read to complete by retrying the read operation
8576 upon EAGAIN. So I'm disabling the DebPrint to avoid
8577 wasting cycles on something that is not a real
8578 problem. Enable if you need to debug something that
8579 bumps into this. */
8580 DebPrint (("sys_read called when read is in progress %d\n",
8581 current_status));
8582 #endif
8583 errno = EWOULDBLOCK;
8584 return -1;
8586 case STATUS_READ_SUCCEEDED:
8587 /* consume read-ahead char */
8588 *buffer++ = cp->chr;
8589 count--;
8590 nchars++;
8591 cp->status = STATUS_READ_ACKNOWLEDGED;
8592 ResetEvent (cp->char_avail);
8594 case STATUS_READ_ACKNOWLEDGED:
8595 case STATUS_CONNECT_FAILED:
8596 break;
8598 default:
8599 DebPrint (("sys_read: bad status %d\n", current_status));
8600 errno = EBADF;
8601 return -1;
8604 if (fd_info[fd].flags & FILE_PIPE)
8606 PeekNamedPipe ((HANDLE) _get_osfhandle (fd), NULL, 0, NULL, &waiting, NULL);
8607 to_read = min (waiting, (DWORD) count);
8609 if (to_read > 0)
8610 nchars += _read (fd, buffer, to_read);
8612 else if (fd_info[fd].flags & FILE_SERIAL)
8614 HANDLE hnd = fd_info[fd].hnd;
8615 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
8616 int rc = 0;
8617 COMMTIMEOUTS ct;
8619 if (count > 0)
8621 /* Configure timeouts for non-blocking read. */
8622 if (!GetCommTimeouts (hnd, &ct))
8624 errno = EIO;
8625 return -1;
8627 ct.ReadIntervalTimeout = MAXDWORD;
8628 ct.ReadTotalTimeoutMultiplier = 0;
8629 ct.ReadTotalTimeoutConstant = 0;
8630 if (!SetCommTimeouts (hnd, &ct))
8632 errno = EIO;
8633 return -1;
8636 if (!ResetEvent (ovl->hEvent))
8638 errno = EIO;
8639 return -1;
8641 if (!ReadFile (hnd, buffer, count, (DWORD*) &rc, ovl))
8643 if (GetLastError () != ERROR_IO_PENDING)
8645 errno = EIO;
8646 return -1;
8648 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
8650 errno = EIO;
8651 return -1;
8654 nchars += rc;
8657 else /* FILE_SOCKET */
8659 if (winsock_lib == NULL) emacs_abort ();
8661 /* When a non-blocking 'connect' call fails,
8662 wait_reading_process_output detects this by calling
8663 'getpeername', and then attempts to obtain the connection
8664 error code by trying to read 1 byte from the socket. If
8665 we try to serve that read by calling 'recv' below, the
8666 error we get is a generic WSAENOTCONN, not the actual
8667 connection error. So instead, we use the actual error
8668 code stashed by '_sys_wait_connect' in cp->errcode.
8669 Alternatively, we could have used 'getsockopt', like on
8670 GNU/Linux, but: (a) I have no idea whether the winsock
8671 version could hang, as it does "on some systems" (see the
8672 comment in process.c); and (b) 'getsockopt' on Windows is
8673 documented to clear the socket error for the entire
8674 process, which I'm not sure is TRT; FIXME. */
8675 if (current_status == STATUS_CONNECT_FAILED
8676 && (fd_info[fd].flags & FILE_CONNECT) != 0
8677 && cp->errcode != 0)
8679 pfn_WSASetLastError (cp->errcode);
8680 set_errno ();
8681 return -1;
8683 /* Do the equivalent of a non-blocking read. */
8684 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONREAD, &waiting);
8685 if (waiting == 0 && nchars == 0)
8687 errno = EWOULDBLOCK;
8688 return -1;
8691 if (waiting)
8693 /* always use binary mode for sockets */
8694 int res = pfn_recv (SOCK_HANDLE (fd), buffer, count, 0);
8695 if (res == SOCKET_ERROR)
8697 set_errno ();
8698 DebPrint (("sys_read.recv failed with error %d on socket %ld\n",
8699 errno, SOCK_HANDLE (fd)));
8700 return -1;
8702 nchars += res;
8706 else
8708 int nread = _read (fd, buffer, count);
8709 if (nread >= 0)
8710 nchars += nread;
8711 else if (nchars == 0)
8712 nchars = nread;
8715 if (nchars <= 0)
8716 fd_info[fd].flags |= FILE_AT_EOF;
8717 /* Perform text mode translation if required. */
8718 else if ((fd_info[fd].flags & FILE_BINARY) == 0)
8720 nchars = crlf_to_lf (nchars, orig_buffer);
8721 /* If buffer contains only CR, return that. To be absolutely
8722 sure we should attempt to read the next char, but in
8723 practice a CR to be followed by LF would not appear by
8724 itself in the buffer. */
8725 if (nchars > 1 && orig_buffer[nchars - 1] == 0x0d)
8727 fd_info[fd].flags |= FILE_LAST_CR;
8728 nchars--;
8732 else
8733 nchars = _read (fd, buffer, count);
8735 return nchars;
8738 /* From w32xfns.c */
8739 extern HANDLE interrupt_handle;
8742 sys_write (int fd, const void * buffer, unsigned int count)
8744 int nchars;
8745 USE_SAFE_ALLOCA;
8747 if (fd < 0)
8749 errno = EBADF;
8750 return -1;
8753 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
8755 if ((fd_info[fd].flags & FILE_WRITE) == 0)
8757 errno = EBADF;
8758 return -1;
8761 /* Perform text mode translation if required. */
8762 if ((fd_info[fd].flags & FILE_BINARY) == 0)
8764 char * tmpbuf;
8765 const unsigned char * src = buffer;
8766 unsigned char * dst;
8767 int nbytes = count;
8769 SAFE_NALLOCA (tmpbuf, 2, count);
8770 dst = (unsigned char *)tmpbuf;
8772 while (1)
8774 unsigned char *next;
8775 /* Copy next line or remaining bytes. */
8776 next = _memccpy (dst, src, '\n', nbytes);
8777 if (next)
8779 /* Copied one line ending with '\n'. */
8780 int copied = next - dst;
8781 nbytes -= copied;
8782 src += copied;
8783 /* Insert '\r' before '\n'. */
8784 next[-1] = '\r';
8785 next[0] = '\n';
8786 dst = next + 1;
8787 count++;
8789 else
8790 /* Copied remaining partial line -> now finished. */
8791 break;
8793 buffer = tmpbuf;
8797 if (fd < MAXDESC && fd_info[fd].flags & FILE_SERIAL)
8799 HANDLE hnd = (HANDLE) _get_osfhandle (fd);
8800 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_write;
8801 HANDLE wait_hnd[2] = { interrupt_handle, ovl->hEvent };
8802 DWORD active = 0;
8804 /* This is async (a.k.a. "overlapped") I/O, so the return value
8805 of FALSE from WriteFile means either an error or the output
8806 will be completed asynchronously (ERROR_IO_PENDING). */
8807 if (!WriteFile (hnd, buffer, count, (DWORD*) &nchars, ovl))
8809 if (GetLastError () != ERROR_IO_PENDING)
8811 errno = EIO;
8812 nchars = -1;
8814 else
8816 /* Wait for the write to complete, and watch C-g while
8817 at that. */
8818 if (detect_input_pending ())
8819 active = MsgWaitForMultipleObjects (2, wait_hnd, FALSE,
8820 INFINITE, QS_ALLINPUT);
8821 else
8822 active = WaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE);
8823 switch (active)
8825 case WAIT_OBJECT_0:
8826 /* User pressed C-g, cancel write, then leave.
8827 Don't bother cleaning up as we may only get stuck
8828 in buggy drivers. */
8829 PurgeComm (hnd, PURGE_TXABORT | PURGE_TXCLEAR);
8830 CancelIo (hnd);
8831 errno = EIO; /* Why not EINTR? */
8832 nchars = -1;
8833 break;
8834 case WAIT_OBJECT_0 + 1:
8835 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &nchars, TRUE))
8837 errno = EIO;
8838 nchars = -1;
8840 break;
8845 else if (fd < MAXDESC && fd_info[fd].flags & FILE_SOCKET)
8847 unsigned long nblock = 0;
8848 if (winsock_lib == NULL) emacs_abort ();
8850 child_process *cp = fd_info[fd].cp;
8852 /* If this is a non-blocking socket whose connection is in
8853 progress or terminated with an error already, return the
8854 proper error code to the caller. */
8855 if (cp != NULL && (fd_info[fd].flags & FILE_CONNECT) != 0)
8857 /* In case connection is in progress, ENOTCONN that would
8858 result from calling pfn_send is not what callers expect. */
8859 if (cp->status != STATUS_CONNECT_FAILED)
8861 errno = EWOULDBLOCK;
8862 return -1;
8864 /* In case connection failed, use the actual error code
8865 stashed by '_sys_wait_connect' in cp->errcode. */
8866 else if (cp->errcode != 0)
8868 pfn_WSASetLastError (cp->errcode);
8869 set_errno ();
8870 return -1;
8874 /* TODO: implement select() properly so non-blocking I/O works. */
8875 /* For now, make sure the write blocks. */
8876 if (fd_info[fd].flags & FILE_NDELAY)
8877 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
8879 nchars = pfn_send (SOCK_HANDLE (fd), buffer, count, 0);
8881 if (nchars == SOCKET_ERROR)
8883 set_errno ();
8884 DebPrint (("sys_write.send failed with error %d on socket %ld\n",
8885 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
8888 /* Set the socket back to non-blocking if it was before,
8889 for other operations that support it. */
8890 if (fd_info[fd].flags & FILE_NDELAY)
8892 nblock = 1;
8893 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
8896 else
8898 /* Some networked filesystems don't like too large writes, so
8899 break them into smaller chunks. See the Comments section of
8900 the MSDN documentation of WriteFile for details behind the
8901 choice of the value of CHUNK below. See also the thread
8902 http://thread.gmane.org/gmane.comp.version-control.git/145294
8903 in the git mailing list. */
8904 const unsigned char *p = buffer;
8905 const bool is_pipe = (fd < MAXDESC
8906 && ((fd_info[fd].flags & (FILE_PIPE | FILE_NDELAY))
8907 == (FILE_PIPE | FILE_NDELAY)));
8908 /* Some programs, notably Node.js's node.exe, seem to never
8909 completely empty the pipe, so writing more than the size of
8910 the pipe's buffer always returns ENOSPC, and we loop forever
8911 between send_process and here. As a workaround, write no
8912 more than the pipe's buffer can hold. */
8913 DWORD pipe_buffer_size;
8914 if (is_pipe)
8916 if (!GetNamedPipeInfo ((HANDLE)_get_osfhandle (fd),
8917 NULL, &pipe_buffer_size, NULL, NULL))
8919 DebPrint (("GetNamedPipeInfo: error %u\n", GetLastError ()));
8920 pipe_buffer_size = 4096;
8923 const unsigned chunk = is_pipe ? pipe_buffer_size : 30 * 1024 * 1024;
8925 nchars = 0;
8926 errno = 0;
8927 while (count > 0)
8929 unsigned this_chunk = count < chunk ? count : chunk;
8930 int n = _write (fd, p, this_chunk);
8932 if (n > 0)
8933 nchars += n;
8934 if (n < 0)
8936 /* When there's no buffer space in a pipe that is in the
8937 non-blocking mode, _write returns ENOSPC. We return
8938 EAGAIN instead, which should trigger the logic in
8939 send_process that enters waiting loop and calls
8940 wait_reading_process_output to allow process input to
8941 be accepted during the wait. Those calls to
8942 wait_reading_process_output allow sys_select to
8943 notice when process input becomes available, thus
8944 avoiding deadlock whereby each side of the pipe is
8945 blocked on write, waiting for the other party to read
8946 its end of the pipe. */
8947 if (errno == ENOSPC && is_pipe)
8948 errno = EAGAIN;
8949 if (nchars == 0)
8950 nchars = -1;
8951 break;
8953 else if (n < this_chunk)
8954 break;
8955 count -= n;
8956 p += n;
8960 SAFE_FREE ();
8961 return nchars;
8965 /* Emulation of SIOCGIFCONF and getifaddrs, see process.c. */
8967 /* Return information about network interface IFNAME, or about all
8968 interfaces (if IFNAME is nil). */
8969 static Lisp_Object
8970 network_interface_get_info (Lisp_Object ifname)
8972 ULONG ainfo_len = sizeof (IP_ADAPTER_INFO);
8973 IP_ADAPTER_INFO *adapter, *ainfo = xmalloc (ainfo_len);
8974 DWORD retval = get_adapters_info (ainfo, &ainfo_len);
8975 Lisp_Object res = Qnil;
8977 if (retval == ERROR_BUFFER_OVERFLOW)
8979 ainfo = xrealloc (ainfo, ainfo_len);
8980 retval = get_adapters_info (ainfo, &ainfo_len);
8983 if (retval == ERROR_SUCCESS)
8985 int eth_count = 0, tr_count = 0, fddi_count = 0, ppp_count = 0;
8986 int sl_count = 0, wlan_count = 0, lo_count = 0, ifx_count = 0;
8987 int if_num;
8988 struct sockaddr_in sa;
8990 /* For the below, we need some winsock functions, so make sure
8991 the winsock DLL is loaded. If we cannot successfully load
8992 it, they will have no use of the information we provide,
8993 anyway, so punt. */
8994 if (!winsock_lib && !init_winsock (1))
8995 goto done;
8997 for (adapter = ainfo; adapter; adapter = adapter->Next)
8999 char namebuf[MAX_ADAPTER_NAME_LENGTH + 4];
9000 u_long ip_addr;
9001 /* Present Unix-compatible interface names, instead of the
9002 Windows names, which are really GUIDs not readable by
9003 humans. */
9004 static const char *ifmt[] = {
9005 "eth%d", "tr%d", "fddi%d", "ppp%d", "sl%d", "wlan%d",
9006 "lo", "ifx%d"
9008 enum {
9009 NONE = -1,
9010 ETHERNET = 0,
9011 TOKENRING = 1,
9012 FDDI = 2,
9013 PPP = 3,
9014 SLIP = 4,
9015 WLAN = 5,
9016 LOOPBACK = 6,
9017 OTHER_IF = 7
9018 } ifmt_idx;
9020 switch (adapter->Type)
9022 case MIB_IF_TYPE_ETHERNET:
9023 /* Windows before Vista reports wireless adapters as
9024 Ethernet. Work around by looking at the Description
9025 string. */
9026 if (strstr (adapter->Description, "Wireless "))
9028 ifmt_idx = WLAN;
9029 if_num = wlan_count++;
9031 else
9033 ifmt_idx = ETHERNET;
9034 if_num = eth_count++;
9036 break;
9037 case MIB_IF_TYPE_TOKENRING:
9038 ifmt_idx = TOKENRING;
9039 if_num = tr_count++;
9040 break;
9041 case MIB_IF_TYPE_FDDI:
9042 ifmt_idx = FDDI;
9043 if_num = fddi_count++;
9044 break;
9045 case MIB_IF_TYPE_PPP:
9046 ifmt_idx = PPP;
9047 if_num = ppp_count++;
9048 break;
9049 case MIB_IF_TYPE_SLIP:
9050 ifmt_idx = SLIP;
9051 if_num = sl_count++;
9052 break;
9053 case IF_TYPE_IEEE80211:
9054 ifmt_idx = WLAN;
9055 if_num = wlan_count++;
9056 break;
9057 case MIB_IF_TYPE_LOOPBACK:
9058 if (lo_count < 0)
9060 ifmt_idx = LOOPBACK;
9061 if_num = lo_count++;
9063 else
9064 ifmt_idx = NONE;
9065 break;
9066 default:
9067 ifmt_idx = OTHER_IF;
9068 if_num = ifx_count++;
9069 break;
9071 if (ifmt_idx == NONE)
9072 continue;
9073 sprintf (namebuf, ifmt[ifmt_idx], if_num);
9075 sa.sin_family = AF_INET;
9076 ip_addr = sys_inet_addr (adapter->IpAddressList.IpAddress.String);
9077 if (ip_addr == INADDR_NONE)
9079 /* Bogus address, skip this interface. */
9080 continue;
9082 sa.sin_addr.s_addr = ip_addr;
9083 sa.sin_port = 0;
9084 if (NILP (ifname))
9085 res = Fcons (Fcons (build_string (namebuf),
9086 conv_sockaddr_to_lisp ((struct sockaddr*) &sa,
9087 sizeof (struct sockaddr))),
9088 res);
9089 else if (strcmp (namebuf, SSDATA (ifname)) == 0)
9091 Lisp_Object hwaddr = Fmake_vector (make_number (6), Qnil);
9092 register struct Lisp_Vector *p = XVECTOR (hwaddr);
9093 Lisp_Object flags = Qnil;
9094 int n;
9095 u_long net_mask;
9097 /* Flags. We guess most of them by type, since the
9098 Windows flags are different and hard to get by. */
9099 flags = Fcons (intern ("up"), flags);
9100 if (ifmt_idx == ETHERNET || ifmt_idx == WLAN)
9102 flags = Fcons (intern ("broadcast"), flags);
9103 flags = Fcons (intern ("multicast"), flags);
9105 flags = Fcons (intern ("running"), flags);
9106 if (ifmt_idx == PPP)
9108 flags = Fcons (intern ("pointopoint"), flags);
9109 flags = Fcons (intern ("noarp"), flags);
9111 if (adapter->HaveWins)
9112 flags = Fcons (intern ("WINS"), flags);
9113 if (adapter->DhcpEnabled)
9114 flags = Fcons (intern ("dynamic"), flags);
9116 res = Fcons (flags, res);
9118 /* Hardware address and its family. */
9119 for (n = 0; n < adapter->AddressLength; n++)
9120 p->contents[n] = make_number ((int) adapter->Address[n]);
9121 /* Windows does not support AF_LINK or AF_PACKET family
9122 of addresses. Use an arbitrary family number that is
9123 identical to what GNU/Linux returns. */
9124 res = Fcons (Fcons (make_number (1), hwaddr), res);
9126 /* Network mask. */
9127 sa.sin_family = AF_INET;
9128 net_mask = sys_inet_addr (adapter->IpAddressList.IpMask.String);
9129 if (net_mask != INADDR_NONE)
9131 sa.sin_addr.s_addr = net_mask;
9132 sa.sin_port = 0;
9133 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
9134 sizeof (struct sockaddr)),
9135 res);
9137 else
9138 res = Fcons (Qnil, res);
9140 sa.sin_family = AF_INET;
9141 if (ip_addr != INADDR_NONE)
9143 /* Broadcast address is only reported by
9144 GetAdaptersAddresses, which is of limited
9145 availability. Generate it on our own. */
9146 u_long bcast_addr = (ip_addr & net_mask) | ~net_mask;
9148 sa.sin_addr.s_addr = bcast_addr;
9149 sa.sin_port = 0;
9150 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
9151 sizeof (struct sockaddr)),
9152 res);
9154 /* IP address. */
9155 sa.sin_addr.s_addr = ip_addr;
9156 sa.sin_port = 0;
9157 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
9158 sizeof (struct sockaddr)),
9159 res);
9161 else
9162 res = Fcons (Qnil, Fcons (Qnil, res));
9165 /* GetAdaptersInfo is documented to not report loopback
9166 interfaces, so we generate one out of thin air. */
9167 if (!lo_count)
9169 sa.sin_family = AF_INET;
9170 sa.sin_port = 0;
9171 if (NILP (ifname))
9173 sa.sin_addr.s_addr = sys_inet_addr ("127.0.0.1");
9174 res = Fcons (Fcons (build_string ("lo"),
9175 conv_sockaddr_to_lisp ((struct sockaddr*) &sa,
9176 sizeof (struct sockaddr))),
9177 res);
9179 else if (strcmp (SSDATA (ifname), "lo") == 0)
9181 res = Fcons (Fcons (intern ("running"),
9182 Fcons (intern ("loopback"),
9183 Fcons (intern ("up"), Qnil))), Qnil);
9184 /* 772 is what 3 different GNU/Linux systems report for
9185 the loopback interface. */
9186 res = Fcons (Fcons (make_number (772),
9187 Fmake_vector (make_number (6),
9188 make_number (0))),
9189 res);
9190 sa.sin_addr.s_addr = sys_inet_addr ("255.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 ("0.0.0.0");
9195 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
9196 sizeof (struct sockaddr)),
9197 res);
9198 sa.sin_addr.s_addr = sys_inet_addr ("127.0.0.1");
9199 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
9200 sizeof (struct sockaddr)),
9201 res);
9207 done:
9208 xfree (ainfo);
9209 return res;
9212 Lisp_Object
9213 network_interface_list (void)
9215 return network_interface_get_info (Qnil);
9218 Lisp_Object
9219 network_interface_info (Lisp_Object ifname)
9221 CHECK_STRING (ifname);
9222 return network_interface_get_info (ifname);
9226 /* The Windows CRT functions are "optimized for speed", so they don't
9227 check for timezone and DST changes if they were last called less
9228 than 1 minute ago (see http://support.microsoft.com/kb/821231). So
9229 all Emacs features that repeatedly call time functions (e.g.,
9230 display-time) are in real danger of missing timezone and DST
9231 changes. Calling tzset before each localtime call fixes that. */
9232 struct tm *
9233 sys_localtime (const time_t *t)
9235 tzset ();
9236 return localtime (t);
9241 /* Try loading LIBRARY_ID from the file(s) specified in
9242 Vdynamic_library_alist. If the library is loaded successfully,
9243 return the handle of the DLL, and record the filename in the
9244 property :loaded-from of LIBRARY_ID. If the library could not be
9245 found, or when it was already loaded (because the handle is not
9246 recorded anywhere, and so is lost after use), return NULL.
9248 We could also save the handle in :loaded-from, but currently
9249 there's no use case for it. */
9250 HMODULE
9251 w32_delayed_load (Lisp_Object library_id)
9253 HMODULE dll_handle = NULL;
9255 CHECK_SYMBOL (library_id);
9257 if (CONSP (Vdynamic_library_alist)
9258 && NILP (Fassq (library_id, Vlibrary_cache)))
9260 Lisp_Object found = Qnil;
9261 Lisp_Object dlls = Fassq (library_id, Vdynamic_library_alist);
9263 if (CONSP (dlls))
9264 for (dlls = XCDR (dlls); CONSP (dlls); dlls = XCDR (dlls))
9266 Lisp_Object dll = XCAR (dlls);
9267 char name[MAX_UTF8_PATH];
9268 DWORD res = -1;
9270 CHECK_STRING (dll);
9271 dll = ENCODE_FILE (dll);
9272 if (w32_unicode_filenames)
9274 wchar_t name_w[MAX_PATH];
9276 filename_to_utf16 (SSDATA (dll), name_w);
9277 dll_handle = LoadLibraryW (name_w);
9278 if (dll_handle)
9280 res = GetModuleFileNameW (dll_handle, name_w,
9281 sizeof (name_w));
9282 if (res > 0)
9283 filename_from_utf16 (name_w, name);
9286 else
9288 char name_a[MAX_PATH];
9290 filename_to_ansi (SSDATA (dll), name_a);
9291 dll_handle = LoadLibraryA (name_a);
9292 if (dll_handle)
9294 res = GetModuleFileNameA (dll_handle, name_a,
9295 sizeof (name_a));
9296 if (res > 0)
9297 filename_from_ansi (name_a, name);
9300 if (dll_handle)
9302 ptrdiff_t len = strlen (name);
9303 found = Fcons (dll,
9304 (res > 0)
9305 /* Possibly truncated */
9306 ? make_specified_string (name, -1, len, 1)
9307 : Qnil);
9308 /* This prevents thread start and end notifications
9309 from being sent to the DLL, for every thread we
9310 start. We don't need those notifications because
9311 threads we create never use any of these DLLs, only
9312 the main thread uses them. This is supposed to
9313 speed up thread creation. */
9314 DisableThreadLibraryCalls (dll_handle);
9315 break;
9319 Fput (library_id, QCloaded_from, found);
9322 return dll_handle;
9326 void
9327 check_windows_init_file (void)
9329 /* A common indication that Emacs is not installed properly is when
9330 it cannot find the Windows installation file. If this file does
9331 not exist in the expected place, tell the user. */
9333 if (!noninteractive && !inhibit_window_system
9334 /* Vload_path is not yet initialized when we are loading
9335 loadup.el. */
9336 && NILP (Vpurify_flag))
9338 Lisp_Object init_file;
9339 int fd;
9341 /* Implementation note: this function runs early during Emacs
9342 startup, before startup.el is run. So Vload_path is still in
9343 its initial unibyte form, but it holds UTF-8 encoded file
9344 names, since init_callproc was already called. So we do not
9345 need to ENCODE_FILE here, but we do need to convert the file
9346 names from UTF-8 to ANSI. */
9347 init_file = build_string ("term/w32-win");
9348 fd = openp (Vload_path, init_file, Fget_load_suffixes (), NULL, Qnil, 0);
9349 if (fd < 0)
9351 Lisp_Object load_path_print = Fprin1_to_string (Vload_path, Qnil);
9352 char *init_file_name = SSDATA (init_file);
9353 char *load_path = SSDATA (load_path_print);
9354 char *buffer = alloca (1024
9355 + strlen (init_file_name)
9356 + strlen (load_path));
9357 char *msg = buffer;
9358 int needed;
9360 sprintf (buffer,
9361 "The Emacs Windows initialization file \"%s.el\" "
9362 "could not be found in your Emacs installation. "
9363 "Emacs checked the following directories for this file:\n"
9364 "\n%s\n\n"
9365 "When Emacs cannot find this file, it usually means that it "
9366 "was not installed properly, or its distribution file was "
9367 "not unpacked properly.\nSee the README.W32 file in the "
9368 "top-level Emacs directory for more information.",
9369 init_file_name, load_path);
9370 needed = pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags,
9371 buffer, -1, NULL, 0);
9372 if (needed > 0)
9374 wchar_t *msg_w = alloca ((needed + 1) * sizeof (wchar_t));
9376 pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags, buffer,
9377 -1, msg_w, needed);
9378 needed = pWideCharToMultiByte (CP_ACP, 0, msg_w, -1,
9379 NULL, 0, NULL, NULL);
9380 if (needed > 0)
9382 char *msg_a = alloca (needed + 1);
9384 pWideCharToMultiByte (CP_ACP, 0, msg_w, -1, msg_a, needed,
9385 NULL, NULL);
9386 msg = msg_a;
9389 MessageBox (NULL,
9390 msg,
9391 "Emacs Abort Dialog",
9392 MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
9393 /* Use the low-level system abort. */
9394 abort ();
9396 else
9398 _close (fd);
9403 void
9404 term_ntproc (int ignored)
9406 (void)ignored;
9408 term_timers ();
9410 /* shutdown the socket interface if necessary */
9411 term_winsock ();
9413 term_w32select ();
9416 void
9417 init_ntproc (int dumping)
9419 sigset_t initial_mask = 0;
9421 /* Initialize the socket interface now if available and requested by
9422 the user by defining PRELOAD_WINSOCK; otherwise loading will be
9423 delayed until open-network-stream is called (w32-has-winsock can
9424 also be used to dynamically load or reload winsock).
9426 Conveniently, init_environment is called before us, so
9427 PRELOAD_WINSOCK can be set in the registry. */
9429 /* Always initialize this correctly. */
9430 winsock_lib = NULL;
9432 if (getenv ("PRELOAD_WINSOCK") != NULL)
9433 init_winsock (TRUE);
9435 /* Initial preparation for subprocess support: replace our standard
9436 handles with non-inheritable versions. */
9438 HANDLE parent;
9439 HANDLE stdin_save = INVALID_HANDLE_VALUE;
9440 HANDLE stdout_save = INVALID_HANDLE_VALUE;
9441 HANDLE stderr_save = INVALID_HANDLE_VALUE;
9443 parent = GetCurrentProcess ();
9445 /* ignore errors when duplicating and closing; typically the
9446 handles will be invalid when running as a gui program. */
9447 DuplicateHandle (parent,
9448 GetStdHandle (STD_INPUT_HANDLE),
9449 parent,
9450 &stdin_save,
9452 FALSE,
9453 DUPLICATE_SAME_ACCESS);
9455 DuplicateHandle (parent,
9456 GetStdHandle (STD_OUTPUT_HANDLE),
9457 parent,
9458 &stdout_save,
9460 FALSE,
9461 DUPLICATE_SAME_ACCESS);
9463 DuplicateHandle (parent,
9464 GetStdHandle (STD_ERROR_HANDLE),
9465 parent,
9466 &stderr_save,
9468 FALSE,
9469 DUPLICATE_SAME_ACCESS);
9471 fclose (stdin);
9472 fclose (stdout);
9473 fclose (stderr);
9475 if (stdin_save != INVALID_HANDLE_VALUE)
9476 _open_osfhandle ((intptr_t) stdin_save, O_TEXT);
9477 else
9478 _open ("nul", O_TEXT | O_NOINHERIT | O_RDONLY);
9479 _fdopen (0, "r");
9481 if (stdout_save != INVALID_HANDLE_VALUE)
9482 _open_osfhandle ((intptr_t) stdout_save, O_TEXT);
9483 else
9484 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
9485 _fdopen (1, "w");
9487 if (stderr_save != INVALID_HANDLE_VALUE)
9488 _open_osfhandle ((intptr_t) stderr_save, O_TEXT);
9489 else
9490 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
9491 _fdopen (2, "w");
9494 /* unfortunately, atexit depends on implementation of malloc */
9495 /* atexit (term_ntproc); */
9496 if (!dumping)
9498 /* Make sure we start with all signals unblocked. */
9499 sigprocmask (SIG_SETMASK, &initial_mask, NULL);
9500 signal (SIGABRT, term_ntproc);
9502 init_timers ();
9504 /* determine which drives are fixed, for GetCachedVolumeInformation */
9506 /* GetDriveType must have trailing backslash. */
9507 char drive[] = "A:\\";
9509 /* Loop over all possible drive letters */
9510 while (*drive <= 'Z')
9512 /* Record if this drive letter refers to a fixed drive. */
9513 fixed_drives[DRIVE_INDEX (*drive)] =
9514 (GetDriveType (drive) == DRIVE_FIXED);
9516 (*drive)++;
9519 /* Reset the volume info cache. */
9520 volume_cache = NULL;
9525 shutdown_handler ensures that buffers' autosave files are
9526 up to date when the user logs off, or the system shuts down.
9528 static BOOL WINAPI
9529 shutdown_handler (DWORD type)
9531 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
9532 if (type == CTRL_CLOSE_EVENT /* User closes console window. */
9533 || type == CTRL_LOGOFF_EVENT /* User logs off. */
9534 || type == CTRL_SHUTDOWN_EVENT) /* User shutsdown. */
9536 /* Shut down cleanly, making sure autosave files are up to date. */
9537 shut_down_emacs (0, Qnil);
9540 /* Allow other handlers to handle this signal. */
9541 return FALSE;
9544 /* On Windows 9X, load UNICOWS.DLL and return its handle, or die. On
9545 NT, return a handle to GDI32.DLL. */
9546 HANDLE
9547 maybe_load_unicows_dll (void)
9549 if (os_subtype == OS_9X)
9551 HANDLE ret = LoadLibrary ("Unicows.dll");
9552 if (ret)
9554 /* These two functions are present on Windows 9X as stubs
9555 that always fail. We need the real implementations from
9556 UNICOWS.DLL, so we must call these functions through
9557 pointers, and assign the correct addresses to these
9558 pointers at program startup (see emacs.c, which calls
9559 this function early on). */
9560 pMultiByteToWideChar =
9561 (MultiByteToWideChar_Proc)GetProcAddress (ret, "MultiByteToWideChar");
9562 pWideCharToMultiByte =
9563 (WideCharToMultiByte_Proc)GetProcAddress (ret, "WideCharToMultiByte");
9564 multiByteToWideCharFlags = MB_ERR_INVALID_CHARS;
9565 return ret;
9567 else
9569 int button;
9571 button = MessageBox (NULL,
9572 "Emacs cannot load the UNICOWS.DLL library.\n"
9573 "This library is essential for using Emacs\n"
9574 "on this system. You need to install it.\n\n"
9575 "Emacs will exit when you click OK.",
9576 "Emacs cannot load UNICOWS.DLL",
9577 MB_ICONERROR | MB_TASKMODAL
9578 | MB_SETFOREGROUND | MB_OK);
9579 switch (button)
9581 case IDOK:
9582 default:
9583 exit (1);
9587 else
9589 /* On NT family of Windows, these two functions are always
9590 linked in, so we just assign their addresses to the 2
9591 pointers; no need for the LoadLibrary dance. */
9592 pMultiByteToWideChar = MultiByteToWideChar;
9593 pWideCharToMultiByte = WideCharToMultiByte;
9594 /* On NT 4.0, though, MB_ERR_INVALID_CHARS is not supported. */
9595 if (w32_major_version < 5)
9596 multiByteToWideCharFlags = 0;
9597 else
9598 multiByteToWideCharFlags = MB_ERR_INVALID_CHARS;
9599 return LoadLibrary ("Gdi32.dll");
9604 globals_of_w32 is used to initialize those global variables that
9605 must always be initialized on startup even when the global variable
9606 initialized is non zero (see the function main in emacs.c).
9608 void
9609 globals_of_w32 (void)
9611 HMODULE kernel32 = GetModuleHandle ("kernel32.dll");
9613 get_process_times_fn = (GetProcessTimes_Proc)
9614 GetProcAddress (kernel32, "GetProcessTimes");
9616 DEFSYM (QCloaded_from, ":loaded-from");
9618 g_b_init_is_windows_9x = 0;
9619 g_b_init_open_process_token = 0;
9620 g_b_init_get_token_information = 0;
9621 g_b_init_lookup_account_sid = 0;
9622 g_b_init_get_sid_sub_authority = 0;
9623 g_b_init_get_sid_sub_authority_count = 0;
9624 g_b_init_get_security_info = 0;
9625 g_b_init_get_file_security_w = 0;
9626 g_b_init_get_file_security_a = 0;
9627 g_b_init_get_security_descriptor_owner = 0;
9628 g_b_init_get_security_descriptor_group = 0;
9629 g_b_init_is_valid_sid = 0;
9630 g_b_init_create_toolhelp32_snapshot = 0;
9631 g_b_init_process32_first = 0;
9632 g_b_init_process32_next = 0;
9633 g_b_init_open_thread_token = 0;
9634 g_b_init_impersonate_self = 0;
9635 g_b_init_revert_to_self = 0;
9636 g_b_init_get_process_memory_info = 0;
9637 g_b_init_get_process_working_set_size = 0;
9638 g_b_init_global_memory_status = 0;
9639 g_b_init_global_memory_status_ex = 0;
9640 g_b_init_equal_sid = 0;
9641 g_b_init_copy_sid = 0;
9642 g_b_init_get_length_sid = 0;
9643 g_b_init_get_native_system_info = 0;
9644 g_b_init_get_system_times = 0;
9645 g_b_init_create_symbolic_link_w = 0;
9646 g_b_init_create_symbolic_link_a = 0;
9647 g_b_init_get_security_descriptor_dacl = 0;
9648 g_b_init_convert_sd_to_sddl = 0;
9649 g_b_init_convert_sddl_to_sd = 0;
9650 g_b_init_is_valid_security_descriptor = 0;
9651 g_b_init_set_file_security_w = 0;
9652 g_b_init_set_file_security_a = 0;
9653 g_b_init_set_named_security_info_w = 0;
9654 g_b_init_set_named_security_info_a = 0;
9655 g_b_init_get_adapters_info = 0;
9656 g_b_init_compare_string_w = 0;
9657 g_b_init_debug_break_process = 0;
9658 num_of_processors = 0;
9659 /* The following sets a handler for shutdown notifications for
9660 console apps. This actually applies to Emacs in both console and
9661 GUI modes, since we had to fool windows into thinking emacs is a
9662 console application to get console mode to work. */
9663 SetConsoleCtrlHandler (shutdown_handler, TRUE);
9665 /* "None" is the default group name on standalone workstations. */
9666 strcpy (dflt_group_name, "None");
9668 /* Reset, in case it has some value inherited from dump time. */
9669 w32_stat_get_owner_group = 0;
9671 /* If w32_unicode_filenames is non-zero, we will be using Unicode
9672 (a.k.a. "wide") APIs to invoke functions that accept file
9673 names. */
9674 if (is_windows_9x ())
9675 w32_unicode_filenames = 0;
9676 else
9677 w32_unicode_filenames = 1;
9679 #ifdef HAVE_MODULES
9680 dynlib_reset_last_error ();
9681 #endif
9683 w32_crypto_hprov = (HCRYPTPROV)0;
9686 /* For make-serial-process */
9688 serial_open (Lisp_Object port_obj)
9690 char *port = SSDATA (port_obj);
9691 HANDLE hnd;
9692 child_process *cp;
9693 int fd = -1;
9695 hnd = CreateFile (port, GENERIC_READ | GENERIC_WRITE, 0, 0,
9696 OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
9697 if (hnd == INVALID_HANDLE_VALUE)
9698 error ("Could not open %s", port);
9699 fd = (int) _open_osfhandle ((intptr_t) hnd, 0);
9700 if (fd == -1)
9701 error ("Could not open %s", port);
9703 cp = new_child ();
9704 if (!cp)
9705 error ("Could not create child process");
9706 cp->fd = fd;
9707 cp->status = STATUS_READ_ACKNOWLEDGED;
9708 fd_info[ fd ].hnd = hnd;
9709 fd_info[ fd ].flags |=
9710 FILE_READ | FILE_WRITE | FILE_BINARY | FILE_SERIAL;
9711 if (fd_info[ fd ].cp != NULL)
9713 error ("fd_info[fd = %d] is already in use", fd);
9715 fd_info[ fd ].cp = cp;
9716 cp->ovl_read.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
9717 if (cp->ovl_read.hEvent == NULL)
9718 error ("Could not create read event");
9719 cp->ovl_write.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
9720 if (cp->ovl_write.hEvent == NULL)
9721 error ("Could not create write event");
9723 return fd;
9726 /* For serial-process-configure */
9727 void
9728 serial_configure (struct Lisp_Process *p, Lisp_Object contact)
9730 Lisp_Object childp2 = Qnil;
9731 Lisp_Object tem = Qnil;
9732 HANDLE hnd;
9733 DCB dcb;
9734 COMMTIMEOUTS ct;
9735 char summary[4] = "???"; /* This usually becomes "8N1". */
9737 if ((fd_info[ p->outfd ].flags & FILE_SERIAL) == 0)
9738 error ("Not a serial process");
9739 hnd = fd_info[ p->outfd ].hnd;
9741 childp2 = Fcopy_sequence (p->childp);
9743 /* Initialize timeouts for blocking read and blocking write. */
9744 if (!GetCommTimeouts (hnd, &ct))
9745 error ("GetCommTimeouts() failed");
9746 ct.ReadIntervalTimeout = 0;
9747 ct.ReadTotalTimeoutMultiplier = 0;
9748 ct.ReadTotalTimeoutConstant = 0;
9749 ct.WriteTotalTimeoutMultiplier = 0;
9750 ct.WriteTotalTimeoutConstant = 0;
9751 if (!SetCommTimeouts (hnd, &ct))
9752 error ("SetCommTimeouts() failed");
9753 /* Read port attributes and prepare default configuration. */
9754 memset (&dcb, 0, sizeof (dcb));
9755 dcb.DCBlength = sizeof (DCB);
9756 if (!GetCommState (hnd, &dcb))
9757 error ("GetCommState() failed");
9758 dcb.fBinary = TRUE;
9759 dcb.fNull = FALSE;
9760 dcb.fAbortOnError = FALSE;
9761 /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
9762 dcb.ErrorChar = 0;
9763 dcb.EofChar = 0;
9764 dcb.EvtChar = 0;
9766 /* Configure speed. */
9767 if (!NILP (Fplist_member (contact, QCspeed)))
9768 tem = Fplist_get (contact, QCspeed);
9769 else
9770 tem = Fplist_get (p->childp, QCspeed);
9771 CHECK_NUMBER (tem);
9772 dcb.BaudRate = XINT (tem);
9773 childp2 = Fplist_put (childp2, QCspeed, tem);
9775 /* Configure bytesize. */
9776 if (!NILP (Fplist_member (contact, QCbytesize)))
9777 tem = Fplist_get (contact, QCbytesize);
9778 else
9779 tem = Fplist_get (p->childp, QCbytesize);
9780 if (NILP (tem))
9781 tem = make_number (8);
9782 CHECK_NUMBER (tem);
9783 if (XINT (tem) != 7 && XINT (tem) != 8)
9784 error (":bytesize must be nil (8), 7, or 8");
9785 dcb.ByteSize = XINT (tem);
9786 summary[0] = XINT (tem) + '0';
9787 childp2 = Fplist_put (childp2, QCbytesize, tem);
9789 /* Configure parity. */
9790 if (!NILP (Fplist_member (contact, QCparity)))
9791 tem = Fplist_get (contact, QCparity);
9792 else
9793 tem = Fplist_get (p->childp, QCparity);
9794 if (!NILP (tem) && !EQ (tem, Qeven) && !EQ (tem, Qodd))
9795 error (":parity must be nil (no parity), `even', or `odd'");
9796 dcb.fParity = FALSE;
9797 dcb.Parity = NOPARITY;
9798 dcb.fErrorChar = FALSE;
9799 if (NILP (tem))
9801 summary[1] = 'N';
9803 else if (EQ (tem, Qeven))
9805 summary[1] = 'E';
9806 dcb.fParity = TRUE;
9807 dcb.Parity = EVENPARITY;
9808 dcb.fErrorChar = TRUE;
9810 else if (EQ (tem, Qodd))
9812 summary[1] = 'O';
9813 dcb.fParity = TRUE;
9814 dcb.Parity = ODDPARITY;
9815 dcb.fErrorChar = TRUE;
9817 childp2 = Fplist_put (childp2, QCparity, tem);
9819 /* Configure stopbits. */
9820 if (!NILP (Fplist_member (contact, QCstopbits)))
9821 tem = Fplist_get (contact, QCstopbits);
9822 else
9823 tem = Fplist_get (p->childp, QCstopbits);
9824 if (NILP (tem))
9825 tem = make_number (1);
9826 CHECK_NUMBER (tem);
9827 if (XINT (tem) != 1 && XINT (tem) != 2)
9828 error (":stopbits must be nil (1 stopbit), 1, or 2");
9829 summary[2] = XINT (tem) + '0';
9830 if (XINT (tem) == 1)
9831 dcb.StopBits = ONESTOPBIT;
9832 else if (XINT (tem) == 2)
9833 dcb.StopBits = TWOSTOPBITS;
9834 childp2 = Fplist_put (childp2, QCstopbits, tem);
9836 /* Configure flowcontrol. */
9837 if (!NILP (Fplist_member (contact, QCflowcontrol)))
9838 tem = Fplist_get (contact, QCflowcontrol);
9839 else
9840 tem = Fplist_get (p->childp, QCflowcontrol);
9841 if (!NILP (tem) && !EQ (tem, Qhw) && !EQ (tem, Qsw))
9842 error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
9843 dcb.fOutxCtsFlow = FALSE;
9844 dcb.fOutxDsrFlow = FALSE;
9845 dcb.fDtrControl = DTR_CONTROL_DISABLE;
9846 dcb.fDsrSensitivity = FALSE;
9847 dcb.fTXContinueOnXoff = FALSE;
9848 dcb.fOutX = FALSE;
9849 dcb.fInX = FALSE;
9850 dcb.fRtsControl = RTS_CONTROL_DISABLE;
9851 dcb.XonChar = 17; /* Control-Q */
9852 dcb.XoffChar = 19; /* Control-S */
9853 if (NILP (tem))
9855 /* Already configured. */
9857 else if (EQ (tem, Qhw))
9859 dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
9860 dcb.fOutxCtsFlow = TRUE;
9862 else if (EQ (tem, Qsw))
9864 dcb.fOutX = TRUE;
9865 dcb.fInX = TRUE;
9867 childp2 = Fplist_put (childp2, QCflowcontrol, tem);
9869 /* Activate configuration. */
9870 if (!SetCommState (hnd, &dcb))
9871 error ("SetCommState() failed");
9873 childp2 = Fplist_put (childp2, QCsummary, build_string (summary));
9874 pset_childp (p, childp2);
9877 /* For make-pipe-process */
9878 void
9879 register_aux_fd (int infd)
9881 child_process *cp;
9883 cp = new_child ();
9884 if (!cp)
9885 error ("Could not create child process");
9886 cp->fd = infd;
9887 cp->status = STATUS_READ_ACKNOWLEDGED;
9889 if (fd_info[ infd ].cp != NULL)
9891 error ("fd_info[fd = %d] is already in use", infd);
9893 fd_info[ infd ].cp = cp;
9894 fd_info[ infd ].hnd = (HANDLE) _get_osfhandle (infd);
9897 #ifdef HAVE_GNUTLS
9899 ssize_t
9900 emacs_gnutls_pull (gnutls_transport_ptr_t p, void* buf, size_t sz)
9902 int n, err;
9903 struct Lisp_Process *process = (struct Lisp_Process *)p;
9904 int fd = process->infd;
9906 n = sys_read (fd, (char*)buf, sz);
9908 if (n >= 0)
9909 return n;
9911 err = errno;
9913 /* Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
9914 if (err == EWOULDBLOCK)
9915 err = EAGAIN;
9917 emacs_gnutls_transport_set_errno (process->gnutls_state, err);
9919 return -1;
9922 ssize_t
9923 emacs_gnutls_push (gnutls_transport_ptr_t p, const void* buf, size_t sz)
9925 struct Lisp_Process *process = (struct Lisp_Process *)p;
9926 int fd = process->outfd;
9927 ssize_t n = sys_write (fd, buf, sz);
9929 /* 0 or more bytes written means everything went fine. */
9930 if (n >= 0)
9931 return n;
9933 /* Negative bytes written means we got an error in errno.
9934 Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
9935 emacs_gnutls_transport_set_errno (process->gnutls_state,
9936 errno == EWOULDBLOCK ? EAGAIN : errno);
9938 return -1;
9940 #endif /* HAVE_GNUTLS */
9942 /* end of w32.c */