; doc/emacs/misc.texi (Network Security): Fix typo.
[emacs.git] / src / w32.c
blobe93aaab9ca1de5d05c8252769a8c2bbe40dd28b4
1 /* Utility and Unix shadow routines for GNU Emacs on the Microsoft Windows API.
3 Copyright (C) 1994-1995, 2000-2018 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 <https://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 *);
85 /* MinGW64 system headers include string.h too early, causing the
86 compiler to emit a warning about sys_strerror having no
87 prototype. */
88 char *sys_strerror (int);
90 #ifdef HAVE_MODULES
91 extern void dynlib_reset_last_error (void);
92 #endif
94 #include "lisp.h"
95 #include "epaths.h" /* for PATH_EXEC */
97 #include <pwd.h>
98 #include <grp.h>
100 #include <windows.h>
101 /* Some versions of compiler define MEMORYSTATUSEX, some don't, so we
102 use a different name to avoid compilation problems. */
103 typedef struct _MEMORY_STATUS_EX {
104 DWORD dwLength;
105 DWORD dwMemoryLoad;
106 DWORDLONG ullTotalPhys;
107 DWORDLONG ullAvailPhys;
108 DWORDLONG ullTotalPageFile;
109 DWORDLONG ullAvailPageFile;
110 DWORDLONG ullTotalVirtual;
111 DWORDLONG ullAvailVirtual;
112 DWORDLONG ullAvailExtendedVirtual;
113 } MEMORY_STATUS_EX,*LPMEMORY_STATUS_EX;
115 /* These are here so that GDB would know about these data types. This
116 allows attaching GDB to Emacs when a fatal exception is triggered
117 and Windows pops up the "application needs to be closed" dialog.
118 At that point, _gnu_exception_handler, the top-level exception
119 handler installed by the MinGW startup code, is somewhere on the
120 call-stack of the main thread, so going to that call frame and
121 looking at the argument to _gnu_exception_handler, which is a
122 PEXCEPTION_POINTERS pointer, can reveal the exception code
123 (excptr->ExceptionRecord->ExceptionCode) and the address where the
124 exception happened (excptr->ExceptionRecord->ExceptionAddress), as
125 well as some additional information specific to the exception. */
126 PEXCEPTION_POINTERS excptr;
127 PEXCEPTION_RECORD excprec;
128 PCONTEXT ctxrec;
130 #include <lmcons.h>
131 #include <shlobj.h>
133 #include <tlhelp32.h>
134 #include <psapi.h>
135 #ifndef _MSC_VER
136 #include <w32api.h>
137 #endif
138 #if _WIN32_WINNT < 0x0500
139 #if !defined (__MINGW32__) || __W32API_MAJOR_VERSION < 3 || (__W32API_MAJOR_VERSION == 3 && __W32API_MINOR_VERSION < 15)
140 /* This either is not in psapi.h or guarded by higher value of
141 _WIN32_WINNT than what we use. w32api supplied with MinGW 3.15
142 defines it in psapi.h */
143 typedef struct _PROCESS_MEMORY_COUNTERS_EX {
144 DWORD cb;
145 DWORD PageFaultCount;
146 SIZE_T PeakWorkingSetSize;
147 SIZE_T WorkingSetSize;
148 SIZE_T QuotaPeakPagedPoolUsage;
149 SIZE_T QuotaPagedPoolUsage;
150 SIZE_T QuotaPeakNonPagedPoolUsage;
151 SIZE_T QuotaNonPagedPoolUsage;
152 SIZE_T PagefileUsage;
153 SIZE_T PeakPagefileUsage;
154 SIZE_T PrivateUsage;
155 } PROCESS_MEMORY_COUNTERS_EX,*PPROCESS_MEMORY_COUNTERS_EX;
156 #endif
157 #endif
159 #include <winioctl.h>
160 #include <aclapi.h>
161 #include <sddl.h>
163 #include <sys/acl.h>
164 #include <acl.h>
166 /* This is not in MinGW's sddl.h (but they are in MSVC headers), so we
167 define them by hand if not already defined. */
168 #ifndef SDDL_REVISION_1
169 #define SDDL_REVISION_1 1
170 #endif /* SDDL_REVISION_1 */
172 #if defined(_MSC_VER) || defined(MINGW_W64)
173 /* MSVC and MinGW64 don't provide the definition of
174 REPARSE_DATA_BUFFER and the associated macros, except on ntifs.h,
175 which cannot be included because it triggers conflicts with other
176 Windows API headers. So we define it here by hand. */
178 typedef struct _REPARSE_DATA_BUFFER {
179 ULONG ReparseTag;
180 USHORT ReparseDataLength;
181 USHORT Reserved;
182 union {
183 struct {
184 USHORT SubstituteNameOffset;
185 USHORT SubstituteNameLength;
186 USHORT PrintNameOffset;
187 USHORT PrintNameLength;
188 ULONG Flags;
189 WCHAR PathBuffer[1];
190 } SymbolicLinkReparseBuffer;
191 struct {
192 USHORT SubstituteNameOffset;
193 USHORT SubstituteNameLength;
194 USHORT PrintNameOffset;
195 USHORT PrintNameLength;
196 WCHAR PathBuffer[1];
197 } MountPointReparseBuffer;
198 struct {
199 UCHAR DataBuffer[1];
200 } GenericReparseBuffer;
201 } DUMMYUNIONNAME;
202 } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
204 #ifndef FILE_DEVICE_FILE_SYSTEM
205 #define FILE_DEVICE_FILE_SYSTEM 9
206 #endif
207 #ifndef METHOD_BUFFERED
208 #define METHOD_BUFFERED 0
209 #endif
210 #ifndef FILE_ANY_ACCESS
211 #define FILE_ANY_ACCESS 0x00000000
212 #endif
213 #ifndef CTL_CODE
214 #define CTL_CODE(t,f,m,a) (((t)<<16)|((a)<<14)|((f)<<2)|(m))
215 #endif
216 /* MinGW64 defines FSCTL_GET_REPARSE_POINT on winioctl.h. */
217 #ifndef FSCTL_GET_REPARSE_POINT
218 #define FSCTL_GET_REPARSE_POINT \
219 CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS)
220 #endif
221 #endif
223 /* TCP connection support. */
224 #include <sys/socket.h>
225 #undef socket
226 #undef bind
227 #undef connect
228 #undef htons
229 #undef ntohs
230 #undef inet_addr
231 #undef gethostname
232 #undef gethostbyname
233 #undef getservbyname
234 #undef getpeername
235 #undef shutdown
236 #undef setsockopt
237 #undef listen
238 #undef getsockname
239 #undef accept
240 #undef recvfrom
241 #undef sendto
243 #include <iphlpapi.h> /* should be after winsock2.h */
245 #include <wincrypt.h>
247 #include <c-strcase.h>
248 #include <utimens.h> /* for fdutimens */
250 #include "w32.h"
251 #include <dirent.h>
252 #include "w32common.h"
253 #include "w32select.h"
254 #include "systime.h" /* for current_timespec, struct timespec */
255 #include "dispextern.h" /* for xstrcasecmp */
256 #include "coding.h" /* for Vlocale_coding_system */
258 #include "careadlinkat.h"
259 #include "allocator.h"
261 /* For Lisp_Process, serial_configure and serial_open. */
262 #include "process.h"
263 #include "systty.h"
265 typedef HRESULT (WINAPI * ShGetFolderPath_fn)
266 (IN HWND, IN int, IN HANDLE, IN DWORD, OUT char *);
268 static DWORD get_rid (PSID);
269 static int is_symlink (const char *);
270 static char * chase_symlinks (const char *);
271 static int enable_privilege (LPCTSTR, BOOL, TOKEN_PRIVILEGES *);
272 static int restore_privilege (TOKEN_PRIVILEGES *);
273 static BOOL WINAPI revert_to_self (void);
275 static int sys_access (const char *, int);
276 extern void *e_malloc (size_t);
277 extern int sys_select (int, SELECT_TYPE *, SELECT_TYPE *, SELECT_TYPE *,
278 const struct timespec *, const sigset_t *);
279 extern int sys_dup (int);
282 /* Initialization states.
284 WARNING: If you add any more such variables for additional APIs,
285 you MUST add initialization for them to globals_of_w32
286 below. This is because these variables might get set
287 to non-NULL values during dumping, but the dumped Emacs
288 cannot reuse those values, because it could be run on a
289 different version of the OS, where API addresses are
290 different. */
291 static BOOL g_b_init_is_windows_9x;
292 static BOOL g_b_init_open_process_token;
293 static BOOL g_b_init_get_token_information;
294 static BOOL g_b_init_lookup_account_sid;
295 static BOOL g_b_init_get_sid_sub_authority;
296 static BOOL g_b_init_get_sid_sub_authority_count;
297 static BOOL g_b_init_get_security_info;
298 static BOOL g_b_init_get_file_security_w;
299 static BOOL g_b_init_get_file_security_a;
300 static BOOL g_b_init_get_security_descriptor_owner;
301 static BOOL g_b_init_get_security_descriptor_group;
302 static BOOL g_b_init_is_valid_sid;
303 static BOOL g_b_init_create_toolhelp32_snapshot;
304 static BOOL g_b_init_process32_first;
305 static BOOL g_b_init_process32_next;
306 static BOOL g_b_init_open_thread_token;
307 static BOOL g_b_init_impersonate_self;
308 static BOOL g_b_init_revert_to_self;
309 static BOOL g_b_init_get_process_memory_info;
310 static BOOL g_b_init_get_process_working_set_size;
311 static BOOL g_b_init_global_memory_status;
312 static BOOL g_b_init_global_memory_status_ex;
313 static BOOL g_b_init_get_length_sid;
314 static BOOL g_b_init_equal_sid;
315 static BOOL g_b_init_copy_sid;
316 static BOOL g_b_init_get_native_system_info;
317 static BOOL g_b_init_get_system_times;
318 static BOOL g_b_init_create_symbolic_link_w;
319 static BOOL g_b_init_create_symbolic_link_a;
320 static BOOL g_b_init_get_security_descriptor_dacl;
321 static BOOL g_b_init_convert_sd_to_sddl;
322 static BOOL g_b_init_convert_sddl_to_sd;
323 static BOOL g_b_init_is_valid_security_descriptor;
324 static BOOL g_b_init_set_file_security_w;
325 static BOOL g_b_init_set_file_security_a;
326 static BOOL g_b_init_set_named_security_info_w;
327 static BOOL g_b_init_set_named_security_info_a;
328 static BOOL g_b_init_get_adapters_info;
329 static BOOL g_b_init_reg_open_key_ex_w;
330 static BOOL g_b_init_reg_query_value_ex_w;
331 static BOOL g_b_init_expand_environment_strings_w;
333 BOOL g_b_init_compare_string_w;
334 BOOL g_b_init_debug_break_process;
337 BEGIN: Wrapper functions around OpenProcessToken
338 and other functions in advapi32.dll that are only
339 supported in Windows NT / 2k / XP
341 /* ** Function pointer typedefs ** */
342 typedef BOOL (WINAPI * OpenProcessToken_Proc) (
343 HANDLE ProcessHandle,
344 DWORD DesiredAccess,
345 PHANDLE TokenHandle);
346 typedef BOOL (WINAPI * GetTokenInformation_Proc) (
347 HANDLE TokenHandle,
348 TOKEN_INFORMATION_CLASS TokenInformationClass,
349 LPVOID TokenInformation,
350 DWORD TokenInformationLength,
351 PDWORD ReturnLength);
352 typedef BOOL (WINAPI * GetProcessTimes_Proc) (
353 HANDLE process_handle,
354 LPFILETIME creation_time,
355 LPFILETIME exit_time,
356 LPFILETIME kernel_time,
357 LPFILETIME user_time);
359 GetProcessTimes_Proc get_process_times_fn = NULL;
361 #ifdef _UNICODE
362 const char * const LookupAccountSid_Name = "LookupAccountSidW";
363 #else
364 const char * const LookupAccountSid_Name = "LookupAccountSidA";
365 #endif
366 typedef BOOL (WINAPI * LookupAccountSid_Proc) (
367 LPCTSTR lpSystemName,
368 PSID Sid,
369 LPTSTR Name,
370 LPDWORD cbName,
371 LPTSTR DomainName,
372 LPDWORD cbDomainName,
373 PSID_NAME_USE peUse);
374 typedef PDWORD (WINAPI * GetSidSubAuthority_Proc) (
375 PSID pSid,
376 DWORD n);
377 typedef PUCHAR (WINAPI * GetSidSubAuthorityCount_Proc) (
378 PSID pSid);
379 typedef DWORD (WINAPI * GetSecurityInfo_Proc) (
380 HANDLE handle,
381 SE_OBJECT_TYPE ObjectType,
382 SECURITY_INFORMATION SecurityInfo,
383 PSID *ppsidOwner,
384 PSID *ppsidGroup,
385 PACL *ppDacl,
386 PACL *ppSacl,
387 PSECURITY_DESCRIPTOR *ppSecurityDescriptor);
388 typedef BOOL (WINAPI * GetFileSecurityW_Proc) (
389 LPCWSTR lpFileName,
390 SECURITY_INFORMATION RequestedInformation,
391 PSECURITY_DESCRIPTOR pSecurityDescriptor,
392 DWORD nLength,
393 LPDWORD lpnLengthNeeded);
394 typedef BOOL (WINAPI * GetFileSecurityA_Proc) (
395 LPCSTR lpFileName,
396 SECURITY_INFORMATION RequestedInformation,
397 PSECURITY_DESCRIPTOR pSecurityDescriptor,
398 DWORD nLength,
399 LPDWORD lpnLengthNeeded);
400 typedef BOOL (WINAPI *SetFileSecurityW_Proc) (
401 LPCWSTR lpFileName,
402 SECURITY_INFORMATION SecurityInformation,
403 PSECURITY_DESCRIPTOR pSecurityDescriptor);
404 typedef BOOL (WINAPI *SetFileSecurityA_Proc) (
405 LPCSTR lpFileName,
406 SECURITY_INFORMATION SecurityInformation,
407 PSECURITY_DESCRIPTOR pSecurityDescriptor);
408 typedef DWORD (WINAPI *SetNamedSecurityInfoW_Proc) (
409 LPCWSTR lpObjectName,
410 SE_OBJECT_TYPE ObjectType,
411 SECURITY_INFORMATION SecurityInformation,
412 PSID psidOwner,
413 PSID psidGroup,
414 PACL pDacl,
415 PACL pSacl);
416 typedef DWORD (WINAPI *SetNamedSecurityInfoA_Proc) (
417 LPCSTR lpObjectName,
418 SE_OBJECT_TYPE ObjectType,
419 SECURITY_INFORMATION SecurityInformation,
420 PSID psidOwner,
421 PSID psidGroup,
422 PACL pDacl,
423 PACL pSacl);
424 typedef BOOL (WINAPI * GetSecurityDescriptorOwner_Proc) (
425 PSECURITY_DESCRIPTOR pSecurityDescriptor,
426 PSID *pOwner,
427 LPBOOL lpbOwnerDefaulted);
428 typedef BOOL (WINAPI * GetSecurityDescriptorGroup_Proc) (
429 PSECURITY_DESCRIPTOR pSecurityDescriptor,
430 PSID *pGroup,
431 LPBOOL lpbGroupDefaulted);
432 typedef BOOL (WINAPI *GetSecurityDescriptorDacl_Proc) (
433 PSECURITY_DESCRIPTOR pSecurityDescriptor,
434 LPBOOL lpbDaclPresent,
435 PACL *pDacl,
436 LPBOOL lpbDaclDefaulted);
437 typedef BOOL (WINAPI * IsValidSid_Proc) (
438 PSID sid);
439 typedef HANDLE (WINAPI * CreateToolhelp32Snapshot_Proc) (
440 DWORD dwFlags,
441 DWORD th32ProcessID);
442 typedef BOOL (WINAPI * Process32First_Proc) (
443 HANDLE hSnapshot,
444 LPPROCESSENTRY32 lppe);
445 typedef BOOL (WINAPI * Process32Next_Proc) (
446 HANDLE hSnapshot,
447 LPPROCESSENTRY32 lppe);
448 typedef BOOL (WINAPI * OpenThreadToken_Proc) (
449 HANDLE ThreadHandle,
450 DWORD DesiredAccess,
451 BOOL OpenAsSelf,
452 PHANDLE TokenHandle);
453 typedef BOOL (WINAPI * ImpersonateSelf_Proc) (
454 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel);
455 typedef BOOL (WINAPI * RevertToSelf_Proc) (void);
456 typedef BOOL (WINAPI * GetProcessMemoryInfo_Proc) (
457 HANDLE Process,
458 PPROCESS_MEMORY_COUNTERS ppsmemCounters,
459 DWORD cb);
460 typedef BOOL (WINAPI * GetProcessWorkingSetSize_Proc) (
461 HANDLE hProcess,
462 PSIZE_T lpMinimumWorkingSetSize,
463 PSIZE_T lpMaximumWorkingSetSize);
464 typedef BOOL (WINAPI * GlobalMemoryStatus_Proc) (
465 LPMEMORYSTATUS lpBuffer);
466 typedef BOOL (WINAPI * GlobalMemoryStatusEx_Proc) (
467 LPMEMORY_STATUS_EX lpBuffer);
468 typedef BOOL (WINAPI * CopySid_Proc) (
469 DWORD nDestinationSidLength,
470 PSID pDestinationSid,
471 PSID pSourceSid);
472 typedef BOOL (WINAPI * EqualSid_Proc) (
473 PSID pSid1,
474 PSID pSid2);
475 typedef DWORD (WINAPI * GetLengthSid_Proc) (
476 PSID pSid);
477 typedef void (WINAPI * GetNativeSystemInfo_Proc) (
478 LPSYSTEM_INFO lpSystemInfo);
479 typedef BOOL (WINAPI * GetSystemTimes_Proc) (
480 LPFILETIME lpIdleTime,
481 LPFILETIME lpKernelTime,
482 LPFILETIME lpUserTime);
483 typedef BOOLEAN (WINAPI *CreateSymbolicLinkW_Proc) (
484 LPCWSTR lpSymlinkFileName,
485 LPCWSTR lpTargetFileName,
486 DWORD dwFlags);
487 typedef BOOLEAN (WINAPI *CreateSymbolicLinkA_Proc) (
488 LPCSTR lpSymlinkFileName,
489 LPCSTR lpTargetFileName,
490 DWORD dwFlags);
491 typedef BOOL (WINAPI *ConvertStringSecurityDescriptorToSecurityDescriptor_Proc) (
492 LPCTSTR StringSecurityDescriptor,
493 DWORD StringSDRevision,
494 PSECURITY_DESCRIPTOR *SecurityDescriptor,
495 PULONG SecurityDescriptorSize);
496 typedef BOOL (WINAPI *ConvertSecurityDescriptorToStringSecurityDescriptor_Proc) (
497 PSECURITY_DESCRIPTOR SecurityDescriptor,
498 DWORD RequestedStringSDRevision,
499 SECURITY_INFORMATION SecurityInformation,
500 LPTSTR *StringSecurityDescriptor,
501 PULONG StringSecurityDescriptorLen);
502 typedef BOOL (WINAPI *IsValidSecurityDescriptor_Proc) (PSECURITY_DESCRIPTOR);
503 typedef DWORD (WINAPI *GetAdaptersInfo_Proc) (
504 PIP_ADAPTER_INFO pAdapterInfo,
505 PULONG pOutBufLen);
507 int (WINAPI *pMultiByteToWideChar)(UINT,DWORD,LPCSTR,int,LPWSTR,int);
508 int (WINAPI *pWideCharToMultiByte)(UINT,DWORD,LPCWSTR,int,LPSTR,int,LPCSTR,LPBOOL);
509 DWORD multiByteToWideCharFlags;
510 typedef LONG (WINAPI *RegOpenKeyExW_Proc) (HKEY,LPCWSTR,DWORD,REGSAM,PHKEY);
511 typedef LONG (WINAPI *RegQueryValueExW_Proc) (HKEY,LPCWSTR,LPDWORD,LPDWORD,LPBYTE,LPDWORD);
512 typedef DWORD (WINAPI *ExpandEnvironmentStringsW_Proc) (LPCWSTR,LPWSTR,DWORD);
514 /* ** A utility function ** */
515 static BOOL
516 is_windows_9x (void)
518 static BOOL s_b_ret = 0;
519 OSVERSIONINFO os_ver;
520 if (g_b_init_is_windows_9x == 0)
522 g_b_init_is_windows_9x = 1;
523 ZeroMemory (&os_ver, sizeof (OSVERSIONINFO));
524 os_ver.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
525 if (GetVersionEx (&os_ver))
527 s_b_ret = (os_ver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
530 return s_b_ret;
533 static Lisp_Object ltime (ULONGLONG);
535 /* Get total user and system times for get-internal-run-time.
536 Returns a list of integers if the times are provided by the OS
537 (NT derivatives), otherwise it returns the result of current-time. */
538 Lisp_Object w32_get_internal_run_time (void);
540 Lisp_Object
541 w32_get_internal_run_time (void)
543 if (get_process_times_fn)
545 FILETIME create, exit, kernel, user;
546 HANDLE proc = GetCurrentProcess ();
547 if ((*get_process_times_fn) (proc, &create, &exit, &kernel, &user))
549 LARGE_INTEGER user_int, kernel_int, total;
550 user_int.LowPart = user.dwLowDateTime;
551 user_int.HighPart = user.dwHighDateTime;
552 kernel_int.LowPart = kernel.dwLowDateTime;
553 kernel_int.HighPart = kernel.dwHighDateTime;
554 total.QuadPart = user_int.QuadPart + kernel_int.QuadPart;
555 return ltime (total.QuadPart);
559 return Fcurrent_time ();
562 /* ** The wrapper functions ** */
564 static BOOL WINAPI
565 open_process_token (HANDLE ProcessHandle,
566 DWORD DesiredAccess,
567 PHANDLE TokenHandle)
569 static OpenProcessToken_Proc s_pfn_Open_Process_Token = NULL;
570 HMODULE hm_advapi32 = NULL;
571 if (is_windows_9x () == TRUE)
573 return FALSE;
575 if (g_b_init_open_process_token == 0)
577 g_b_init_open_process_token = 1;
578 hm_advapi32 = LoadLibrary ("Advapi32.dll");
579 s_pfn_Open_Process_Token =
580 (OpenProcessToken_Proc) GetProcAddress (hm_advapi32, "OpenProcessToken");
582 if (s_pfn_Open_Process_Token == NULL)
584 return FALSE;
586 return (
587 s_pfn_Open_Process_Token (
588 ProcessHandle,
589 DesiredAccess,
590 TokenHandle)
594 static BOOL WINAPI
595 get_token_information (HANDLE TokenHandle,
596 TOKEN_INFORMATION_CLASS TokenInformationClass,
597 LPVOID TokenInformation,
598 DWORD TokenInformationLength,
599 PDWORD ReturnLength)
601 static GetTokenInformation_Proc s_pfn_Get_Token_Information = NULL;
602 HMODULE hm_advapi32 = NULL;
603 if (is_windows_9x () == TRUE)
605 return FALSE;
607 if (g_b_init_get_token_information == 0)
609 g_b_init_get_token_information = 1;
610 hm_advapi32 = LoadLibrary ("Advapi32.dll");
611 s_pfn_Get_Token_Information =
612 (GetTokenInformation_Proc) GetProcAddress (hm_advapi32, "GetTokenInformation");
614 if (s_pfn_Get_Token_Information == NULL)
616 return FALSE;
618 return (
619 s_pfn_Get_Token_Information (
620 TokenHandle,
621 TokenInformationClass,
622 TokenInformation,
623 TokenInformationLength,
624 ReturnLength)
628 static BOOL WINAPI
629 lookup_account_sid (LPCTSTR lpSystemName,
630 PSID Sid,
631 LPTSTR Name,
632 LPDWORD cbName,
633 LPTSTR DomainName,
634 LPDWORD cbDomainName,
635 PSID_NAME_USE peUse)
637 static LookupAccountSid_Proc s_pfn_Lookup_Account_Sid = NULL;
638 HMODULE hm_advapi32 = NULL;
639 if (is_windows_9x () == TRUE)
641 return FALSE;
643 if (g_b_init_lookup_account_sid == 0)
645 g_b_init_lookup_account_sid = 1;
646 hm_advapi32 = LoadLibrary ("Advapi32.dll");
647 s_pfn_Lookup_Account_Sid =
648 (LookupAccountSid_Proc) GetProcAddress (hm_advapi32, LookupAccountSid_Name);
650 if (s_pfn_Lookup_Account_Sid == NULL)
652 return FALSE;
654 return (
655 s_pfn_Lookup_Account_Sid (
656 lpSystemName,
657 Sid,
658 Name,
659 cbName,
660 DomainName,
661 cbDomainName,
662 peUse)
666 static PDWORD WINAPI
667 get_sid_sub_authority (PSID pSid, DWORD n)
669 static GetSidSubAuthority_Proc s_pfn_Get_Sid_Sub_Authority = NULL;
670 static DWORD zero = 0U;
671 HMODULE hm_advapi32 = NULL;
672 if (is_windows_9x () == TRUE)
674 return &zero;
676 if (g_b_init_get_sid_sub_authority == 0)
678 g_b_init_get_sid_sub_authority = 1;
679 hm_advapi32 = LoadLibrary ("Advapi32.dll");
680 s_pfn_Get_Sid_Sub_Authority =
681 (GetSidSubAuthority_Proc) GetProcAddress (
682 hm_advapi32, "GetSidSubAuthority");
684 if (s_pfn_Get_Sid_Sub_Authority == NULL)
686 return &zero;
688 return (s_pfn_Get_Sid_Sub_Authority (pSid, n));
691 static PUCHAR WINAPI
692 get_sid_sub_authority_count (PSID pSid)
694 static GetSidSubAuthorityCount_Proc s_pfn_Get_Sid_Sub_Authority_Count = NULL;
695 static UCHAR zero = 0U;
696 HMODULE hm_advapi32 = NULL;
697 if (is_windows_9x () == TRUE)
699 return &zero;
701 if (g_b_init_get_sid_sub_authority_count == 0)
703 g_b_init_get_sid_sub_authority_count = 1;
704 hm_advapi32 = LoadLibrary ("Advapi32.dll");
705 s_pfn_Get_Sid_Sub_Authority_Count =
706 (GetSidSubAuthorityCount_Proc) GetProcAddress (
707 hm_advapi32, "GetSidSubAuthorityCount");
709 if (s_pfn_Get_Sid_Sub_Authority_Count == NULL)
711 return &zero;
713 return (s_pfn_Get_Sid_Sub_Authority_Count (pSid));
716 static DWORD WINAPI
717 get_security_info (HANDLE handle,
718 SE_OBJECT_TYPE ObjectType,
719 SECURITY_INFORMATION SecurityInfo,
720 PSID *ppsidOwner,
721 PSID *ppsidGroup,
722 PACL *ppDacl,
723 PACL *ppSacl,
724 PSECURITY_DESCRIPTOR *ppSecurityDescriptor)
726 static GetSecurityInfo_Proc s_pfn_Get_Security_Info = NULL;
727 HMODULE hm_advapi32 = NULL;
728 if (is_windows_9x () == TRUE)
730 return FALSE;
732 if (g_b_init_get_security_info == 0)
734 g_b_init_get_security_info = 1;
735 hm_advapi32 = LoadLibrary ("Advapi32.dll");
736 s_pfn_Get_Security_Info =
737 (GetSecurityInfo_Proc) GetProcAddress (
738 hm_advapi32, "GetSecurityInfo");
740 if (s_pfn_Get_Security_Info == NULL)
742 return FALSE;
744 return (s_pfn_Get_Security_Info (handle, ObjectType, SecurityInfo,
745 ppsidOwner, ppsidGroup, ppDacl, ppSacl,
746 ppSecurityDescriptor));
749 static BOOL WINAPI
750 get_file_security (const char *lpFileName,
751 SECURITY_INFORMATION RequestedInformation,
752 PSECURITY_DESCRIPTOR pSecurityDescriptor,
753 DWORD nLength,
754 LPDWORD lpnLengthNeeded)
756 static GetFileSecurityA_Proc s_pfn_Get_File_SecurityA = NULL;
757 static GetFileSecurityW_Proc s_pfn_Get_File_SecurityW = NULL;
758 HMODULE hm_advapi32 = NULL;
759 if (is_windows_9x () == TRUE)
761 errno = ENOTSUP;
762 return FALSE;
764 if (w32_unicode_filenames)
766 wchar_t filename_w[MAX_PATH];
768 if (g_b_init_get_file_security_w == 0)
770 g_b_init_get_file_security_w = 1;
771 hm_advapi32 = LoadLibrary ("Advapi32.dll");
772 s_pfn_Get_File_SecurityW =
773 (GetFileSecurityW_Proc) GetProcAddress (hm_advapi32,
774 "GetFileSecurityW");
776 if (s_pfn_Get_File_SecurityW == NULL)
778 errno = ENOTSUP;
779 return FALSE;
781 filename_to_utf16 (lpFileName, filename_w);
782 return (s_pfn_Get_File_SecurityW (filename_w, RequestedInformation,
783 pSecurityDescriptor, nLength,
784 lpnLengthNeeded));
786 else
788 char filename_a[MAX_PATH];
790 if (g_b_init_get_file_security_a == 0)
792 g_b_init_get_file_security_a = 1;
793 hm_advapi32 = LoadLibrary ("Advapi32.dll");
794 s_pfn_Get_File_SecurityA =
795 (GetFileSecurityA_Proc) GetProcAddress (hm_advapi32,
796 "GetFileSecurityA");
798 if (s_pfn_Get_File_SecurityA == NULL)
800 errno = ENOTSUP;
801 return FALSE;
803 filename_to_ansi (lpFileName, filename_a);
804 return (s_pfn_Get_File_SecurityA (filename_a, RequestedInformation,
805 pSecurityDescriptor, nLength,
806 lpnLengthNeeded));
810 static BOOL WINAPI
811 set_file_security (const char *lpFileName,
812 SECURITY_INFORMATION SecurityInformation,
813 PSECURITY_DESCRIPTOR pSecurityDescriptor)
815 static SetFileSecurityW_Proc s_pfn_Set_File_SecurityW = NULL;
816 static SetFileSecurityA_Proc s_pfn_Set_File_SecurityA = NULL;
817 HMODULE hm_advapi32 = NULL;
818 if (is_windows_9x () == TRUE)
820 errno = ENOTSUP;
821 return FALSE;
823 if (w32_unicode_filenames)
825 wchar_t filename_w[MAX_PATH];
827 if (g_b_init_set_file_security_w == 0)
829 g_b_init_set_file_security_w = 1;
830 hm_advapi32 = LoadLibrary ("Advapi32.dll");
831 s_pfn_Set_File_SecurityW =
832 (SetFileSecurityW_Proc) GetProcAddress (hm_advapi32,
833 "SetFileSecurityW");
835 if (s_pfn_Set_File_SecurityW == NULL)
837 errno = ENOTSUP;
838 return FALSE;
840 filename_to_utf16 (lpFileName, filename_w);
841 return (s_pfn_Set_File_SecurityW (filename_w, SecurityInformation,
842 pSecurityDescriptor));
844 else
846 char filename_a[MAX_PATH];
848 if (g_b_init_set_file_security_a == 0)
850 g_b_init_set_file_security_a = 1;
851 hm_advapi32 = LoadLibrary ("Advapi32.dll");
852 s_pfn_Set_File_SecurityA =
853 (SetFileSecurityA_Proc) GetProcAddress (hm_advapi32,
854 "SetFileSecurityA");
856 if (s_pfn_Set_File_SecurityA == NULL)
858 errno = ENOTSUP;
859 return FALSE;
861 filename_to_ansi (lpFileName, filename_a);
862 return (s_pfn_Set_File_SecurityA (filename_a, SecurityInformation,
863 pSecurityDescriptor));
867 static DWORD WINAPI
868 set_named_security_info (LPCTSTR lpObjectName,
869 SE_OBJECT_TYPE ObjectType,
870 SECURITY_INFORMATION SecurityInformation,
871 PSID psidOwner,
872 PSID psidGroup,
873 PACL pDacl,
874 PACL pSacl)
876 static SetNamedSecurityInfoW_Proc s_pfn_Set_Named_Security_InfoW = NULL;
877 static SetNamedSecurityInfoA_Proc s_pfn_Set_Named_Security_InfoA = NULL;
878 HMODULE hm_advapi32 = NULL;
879 if (is_windows_9x () == TRUE)
881 errno = ENOTSUP;
882 return ENOTSUP;
884 if (w32_unicode_filenames)
886 wchar_t filename_w[MAX_PATH];
888 if (g_b_init_set_named_security_info_w == 0)
890 g_b_init_set_named_security_info_w = 1;
891 hm_advapi32 = LoadLibrary ("Advapi32.dll");
892 s_pfn_Set_Named_Security_InfoW =
893 (SetNamedSecurityInfoW_Proc) GetProcAddress (hm_advapi32,
894 "SetNamedSecurityInfoW");
896 if (s_pfn_Set_Named_Security_InfoW == NULL)
898 errno = ENOTSUP;
899 return ENOTSUP;
901 filename_to_utf16 (lpObjectName, filename_w);
902 return (s_pfn_Set_Named_Security_InfoW (filename_w, ObjectType,
903 SecurityInformation, psidOwner,
904 psidGroup, pDacl, pSacl));
906 else
908 char filename_a[MAX_PATH];
910 if (g_b_init_set_named_security_info_a == 0)
912 g_b_init_set_named_security_info_a = 1;
913 hm_advapi32 = LoadLibrary ("Advapi32.dll");
914 s_pfn_Set_Named_Security_InfoA =
915 (SetNamedSecurityInfoA_Proc) GetProcAddress (hm_advapi32,
916 "SetNamedSecurityInfoA");
918 if (s_pfn_Set_Named_Security_InfoA == NULL)
920 errno = ENOTSUP;
921 return ENOTSUP;
923 filename_to_ansi (lpObjectName, filename_a);
924 return (s_pfn_Set_Named_Security_InfoA (filename_a, ObjectType,
925 SecurityInformation, psidOwner,
926 psidGroup, pDacl, pSacl));
930 static BOOL WINAPI
931 get_security_descriptor_owner (PSECURITY_DESCRIPTOR pSecurityDescriptor,
932 PSID *pOwner,
933 LPBOOL lpbOwnerDefaulted)
935 static GetSecurityDescriptorOwner_Proc s_pfn_Get_Security_Descriptor_Owner = NULL;
936 HMODULE hm_advapi32 = NULL;
937 if (is_windows_9x () == TRUE)
939 errno = ENOTSUP;
940 return FALSE;
942 if (g_b_init_get_security_descriptor_owner == 0)
944 g_b_init_get_security_descriptor_owner = 1;
945 hm_advapi32 = LoadLibrary ("Advapi32.dll");
946 s_pfn_Get_Security_Descriptor_Owner =
947 (GetSecurityDescriptorOwner_Proc) GetProcAddress (
948 hm_advapi32, "GetSecurityDescriptorOwner");
950 if (s_pfn_Get_Security_Descriptor_Owner == NULL)
952 errno = ENOTSUP;
953 return FALSE;
955 return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor, pOwner,
956 lpbOwnerDefaulted));
959 static BOOL WINAPI
960 get_security_descriptor_group (PSECURITY_DESCRIPTOR pSecurityDescriptor,
961 PSID *pGroup,
962 LPBOOL lpbGroupDefaulted)
964 static GetSecurityDescriptorGroup_Proc s_pfn_Get_Security_Descriptor_Group = NULL;
965 HMODULE hm_advapi32 = NULL;
966 if (is_windows_9x () == TRUE)
968 errno = ENOTSUP;
969 return FALSE;
971 if (g_b_init_get_security_descriptor_group == 0)
973 g_b_init_get_security_descriptor_group = 1;
974 hm_advapi32 = LoadLibrary ("Advapi32.dll");
975 s_pfn_Get_Security_Descriptor_Group =
976 (GetSecurityDescriptorGroup_Proc) GetProcAddress (
977 hm_advapi32, "GetSecurityDescriptorGroup");
979 if (s_pfn_Get_Security_Descriptor_Group == NULL)
981 errno = ENOTSUP;
982 return FALSE;
984 return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor, pGroup,
985 lpbGroupDefaulted));
988 static BOOL WINAPI
989 get_security_descriptor_dacl (PSECURITY_DESCRIPTOR pSecurityDescriptor,
990 LPBOOL lpbDaclPresent,
991 PACL *pDacl,
992 LPBOOL lpbDaclDefaulted)
994 static GetSecurityDescriptorDacl_Proc s_pfn_Get_Security_Descriptor_Dacl = NULL;
995 HMODULE hm_advapi32 = NULL;
996 if (is_windows_9x () == TRUE)
998 errno = ENOTSUP;
999 return FALSE;
1001 if (g_b_init_get_security_descriptor_dacl == 0)
1003 g_b_init_get_security_descriptor_dacl = 1;
1004 hm_advapi32 = LoadLibrary ("Advapi32.dll");
1005 s_pfn_Get_Security_Descriptor_Dacl =
1006 (GetSecurityDescriptorDacl_Proc) GetProcAddress (
1007 hm_advapi32, "GetSecurityDescriptorDacl");
1009 if (s_pfn_Get_Security_Descriptor_Dacl == NULL)
1011 errno = ENOTSUP;
1012 return FALSE;
1014 return (s_pfn_Get_Security_Descriptor_Dacl (pSecurityDescriptor,
1015 lpbDaclPresent, pDacl,
1016 lpbDaclDefaulted));
1019 static BOOL WINAPI
1020 is_valid_sid (PSID sid)
1022 static IsValidSid_Proc s_pfn_Is_Valid_Sid = NULL;
1023 HMODULE hm_advapi32 = NULL;
1024 if (is_windows_9x () == TRUE)
1026 return FALSE;
1028 if (g_b_init_is_valid_sid == 0)
1030 g_b_init_is_valid_sid = 1;
1031 hm_advapi32 = LoadLibrary ("Advapi32.dll");
1032 s_pfn_Is_Valid_Sid =
1033 (IsValidSid_Proc) GetProcAddress (
1034 hm_advapi32, "IsValidSid");
1036 if (s_pfn_Is_Valid_Sid == NULL)
1038 return FALSE;
1040 return (s_pfn_Is_Valid_Sid (sid));
1043 static BOOL WINAPI
1044 equal_sid (PSID sid1, PSID sid2)
1046 static EqualSid_Proc s_pfn_Equal_Sid = NULL;
1047 HMODULE hm_advapi32 = NULL;
1048 if (is_windows_9x () == TRUE)
1050 return FALSE;
1052 if (g_b_init_equal_sid == 0)
1054 g_b_init_equal_sid = 1;
1055 hm_advapi32 = LoadLibrary ("Advapi32.dll");
1056 s_pfn_Equal_Sid =
1057 (EqualSid_Proc) GetProcAddress (
1058 hm_advapi32, "EqualSid");
1060 if (s_pfn_Equal_Sid == NULL)
1062 return FALSE;
1064 return (s_pfn_Equal_Sid (sid1, sid2));
1067 static DWORD WINAPI
1068 get_length_sid (PSID sid)
1070 static GetLengthSid_Proc s_pfn_Get_Length_Sid = NULL;
1071 HMODULE hm_advapi32 = NULL;
1072 if (is_windows_9x () == TRUE)
1074 return 0;
1076 if (g_b_init_get_length_sid == 0)
1078 g_b_init_get_length_sid = 1;
1079 hm_advapi32 = LoadLibrary ("Advapi32.dll");
1080 s_pfn_Get_Length_Sid =
1081 (GetLengthSid_Proc) GetProcAddress (
1082 hm_advapi32, "GetLengthSid");
1084 if (s_pfn_Get_Length_Sid == NULL)
1086 return 0;
1088 return (s_pfn_Get_Length_Sid (sid));
1091 static BOOL WINAPI
1092 copy_sid (DWORD destlen, PSID dest, PSID src)
1094 static CopySid_Proc s_pfn_Copy_Sid = NULL;
1095 HMODULE hm_advapi32 = NULL;
1096 if (is_windows_9x () == TRUE)
1098 return FALSE;
1100 if (g_b_init_copy_sid == 0)
1102 g_b_init_copy_sid = 1;
1103 hm_advapi32 = LoadLibrary ("Advapi32.dll");
1104 s_pfn_Copy_Sid =
1105 (CopySid_Proc) GetProcAddress (
1106 hm_advapi32, "CopySid");
1108 if (s_pfn_Copy_Sid == NULL)
1110 return FALSE;
1112 return (s_pfn_Copy_Sid (destlen, dest, src));
1116 END: Wrapper functions around OpenProcessToken
1117 and other functions in advapi32.dll that are only
1118 supported in Windows NT / 2k / XP
1121 static void WINAPI
1122 get_native_system_info (LPSYSTEM_INFO lpSystemInfo)
1124 static GetNativeSystemInfo_Proc s_pfn_Get_Native_System_Info = NULL;
1125 if (is_windows_9x () != TRUE)
1127 if (g_b_init_get_native_system_info == 0)
1129 g_b_init_get_native_system_info = 1;
1130 s_pfn_Get_Native_System_Info =
1131 (GetNativeSystemInfo_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1132 "GetNativeSystemInfo");
1134 if (s_pfn_Get_Native_System_Info != NULL)
1135 s_pfn_Get_Native_System_Info (lpSystemInfo);
1137 else
1138 lpSystemInfo->dwNumberOfProcessors = -1;
1141 static BOOL WINAPI
1142 get_system_times (LPFILETIME lpIdleTime,
1143 LPFILETIME lpKernelTime,
1144 LPFILETIME lpUserTime)
1146 static GetSystemTimes_Proc s_pfn_Get_System_times = NULL;
1147 if (is_windows_9x () == TRUE)
1149 return FALSE;
1151 if (g_b_init_get_system_times == 0)
1153 g_b_init_get_system_times = 1;
1154 s_pfn_Get_System_times =
1155 (GetSystemTimes_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1156 "GetSystemTimes");
1158 if (s_pfn_Get_System_times == NULL)
1159 return FALSE;
1160 return (s_pfn_Get_System_times (lpIdleTime, lpKernelTime, lpUserTime));
1163 static BOOLEAN WINAPI
1164 create_symbolic_link (LPCSTR lpSymlinkFilename,
1165 LPCSTR lpTargetFileName,
1166 DWORD dwFlags)
1168 static CreateSymbolicLinkW_Proc s_pfn_Create_Symbolic_LinkW = NULL;
1169 static CreateSymbolicLinkA_Proc s_pfn_Create_Symbolic_LinkA = NULL;
1170 BOOLEAN retval;
1172 if (is_windows_9x () == TRUE)
1174 errno = ENOSYS;
1175 return 0;
1177 if (w32_unicode_filenames)
1179 wchar_t symfn_w[MAX_PATH], tgtfn_w[MAX_PATH];
1181 if (g_b_init_create_symbolic_link_w == 0)
1183 g_b_init_create_symbolic_link_w = 1;
1184 s_pfn_Create_Symbolic_LinkW =
1185 (CreateSymbolicLinkW_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1186 "CreateSymbolicLinkW");
1188 if (s_pfn_Create_Symbolic_LinkW == NULL)
1190 errno = ENOSYS;
1191 return 0;
1194 filename_to_utf16 (lpSymlinkFilename, symfn_w);
1195 filename_to_utf16 (lpTargetFileName, tgtfn_w);
1196 retval = s_pfn_Create_Symbolic_LinkW (symfn_w, tgtfn_w, dwFlags);
1197 /* If we were denied creation of the symlink, try again after
1198 enabling the SeCreateSymbolicLinkPrivilege for our process. */
1199 if (!retval)
1201 TOKEN_PRIVILEGES priv_current;
1203 if (enable_privilege (SE_CREATE_SYMBOLIC_LINK_NAME, TRUE,
1204 &priv_current))
1206 retval = s_pfn_Create_Symbolic_LinkW (symfn_w, tgtfn_w, dwFlags);
1207 restore_privilege (&priv_current);
1208 revert_to_self ();
1212 else
1214 char symfn_a[MAX_PATH], tgtfn_a[MAX_PATH];
1216 if (g_b_init_create_symbolic_link_a == 0)
1218 g_b_init_create_symbolic_link_a = 1;
1219 s_pfn_Create_Symbolic_LinkA =
1220 (CreateSymbolicLinkA_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1221 "CreateSymbolicLinkA");
1223 if (s_pfn_Create_Symbolic_LinkA == NULL)
1225 errno = ENOSYS;
1226 return 0;
1229 filename_to_ansi (lpSymlinkFilename, symfn_a);
1230 filename_to_ansi (lpTargetFileName, tgtfn_a);
1231 retval = s_pfn_Create_Symbolic_LinkA (symfn_a, tgtfn_a, dwFlags);
1232 /* If we were denied creation of the symlink, try again after
1233 enabling the SeCreateSymbolicLinkPrivilege for our process. */
1234 if (!retval)
1236 TOKEN_PRIVILEGES priv_current;
1238 if (enable_privilege (SE_CREATE_SYMBOLIC_LINK_NAME, TRUE,
1239 &priv_current))
1241 retval = s_pfn_Create_Symbolic_LinkA (symfn_a, tgtfn_a, dwFlags);
1242 restore_privilege (&priv_current);
1243 revert_to_self ();
1247 return retval;
1250 static BOOL WINAPI
1251 is_valid_security_descriptor (PSECURITY_DESCRIPTOR pSecurityDescriptor)
1253 static IsValidSecurityDescriptor_Proc s_pfn_Is_Valid_Security_Descriptor_Proc = NULL;
1255 if (is_windows_9x () == TRUE)
1257 errno = ENOTSUP;
1258 return FALSE;
1261 if (g_b_init_is_valid_security_descriptor == 0)
1263 g_b_init_is_valid_security_descriptor = 1;
1264 s_pfn_Is_Valid_Security_Descriptor_Proc =
1265 (IsValidSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1266 "IsValidSecurityDescriptor");
1268 if (s_pfn_Is_Valid_Security_Descriptor_Proc == NULL)
1270 errno = ENOTSUP;
1271 return FALSE;
1274 return s_pfn_Is_Valid_Security_Descriptor_Proc (pSecurityDescriptor);
1277 static BOOL WINAPI
1278 convert_sd_to_sddl (PSECURITY_DESCRIPTOR SecurityDescriptor,
1279 DWORD RequestedStringSDRevision,
1280 SECURITY_INFORMATION SecurityInformation,
1281 LPTSTR *StringSecurityDescriptor,
1282 PULONG StringSecurityDescriptorLen)
1284 static ConvertSecurityDescriptorToStringSecurityDescriptor_Proc s_pfn_Convert_SD_To_SDDL = NULL;
1285 BOOL retval;
1287 if (is_windows_9x () == TRUE)
1289 errno = ENOTSUP;
1290 return FALSE;
1293 if (g_b_init_convert_sd_to_sddl == 0)
1295 g_b_init_convert_sd_to_sddl = 1;
1296 #ifdef _UNICODE
1297 s_pfn_Convert_SD_To_SDDL =
1298 (ConvertSecurityDescriptorToStringSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1299 "ConvertSecurityDescriptorToStringSecurityDescriptorW");
1300 #else
1301 s_pfn_Convert_SD_To_SDDL =
1302 (ConvertSecurityDescriptorToStringSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1303 "ConvertSecurityDescriptorToStringSecurityDescriptorA");
1304 #endif
1306 if (s_pfn_Convert_SD_To_SDDL == NULL)
1308 errno = ENOTSUP;
1309 return FALSE;
1312 retval = s_pfn_Convert_SD_To_SDDL (SecurityDescriptor,
1313 RequestedStringSDRevision,
1314 SecurityInformation,
1315 StringSecurityDescriptor,
1316 StringSecurityDescriptorLen);
1318 return retval;
1321 static BOOL WINAPI
1322 convert_sddl_to_sd (LPCTSTR StringSecurityDescriptor,
1323 DWORD StringSDRevision,
1324 PSECURITY_DESCRIPTOR *SecurityDescriptor,
1325 PULONG SecurityDescriptorSize)
1327 static ConvertStringSecurityDescriptorToSecurityDescriptor_Proc s_pfn_Convert_SDDL_To_SD = NULL;
1328 BOOL retval;
1330 if (is_windows_9x () == TRUE)
1332 errno = ENOTSUP;
1333 return FALSE;
1336 if (g_b_init_convert_sddl_to_sd == 0)
1338 g_b_init_convert_sddl_to_sd = 1;
1339 #ifdef _UNICODE
1340 s_pfn_Convert_SDDL_To_SD =
1341 (ConvertStringSecurityDescriptorToSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1342 "ConvertStringSecurityDescriptorToSecurityDescriptorW");
1343 #else
1344 s_pfn_Convert_SDDL_To_SD =
1345 (ConvertStringSecurityDescriptorToSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1346 "ConvertStringSecurityDescriptorToSecurityDescriptorA");
1347 #endif
1349 if (s_pfn_Convert_SDDL_To_SD == NULL)
1351 errno = ENOTSUP;
1352 return FALSE;
1355 retval = s_pfn_Convert_SDDL_To_SD (StringSecurityDescriptor,
1356 StringSDRevision,
1357 SecurityDescriptor,
1358 SecurityDescriptorSize);
1360 return retval;
1363 static DWORD WINAPI
1364 get_adapters_info (PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen)
1366 static GetAdaptersInfo_Proc s_pfn_Get_Adapters_Info = NULL;
1367 HMODULE hm_iphlpapi = NULL;
1369 if (is_windows_9x () == TRUE)
1370 return ERROR_NOT_SUPPORTED;
1372 if (g_b_init_get_adapters_info == 0)
1374 g_b_init_get_adapters_info = 1;
1375 hm_iphlpapi = LoadLibrary ("Iphlpapi.dll");
1376 if (hm_iphlpapi)
1377 s_pfn_Get_Adapters_Info = (GetAdaptersInfo_Proc)
1378 GetProcAddress (hm_iphlpapi, "GetAdaptersInfo");
1380 if (s_pfn_Get_Adapters_Info == NULL)
1381 return ERROR_NOT_SUPPORTED;
1382 return s_pfn_Get_Adapters_Info (pAdapterInfo, pOutBufLen);
1385 static LONG WINAPI
1386 reg_open_key_ex_w (HKEY hkey, LPCWSTR lpSubKey, DWORD ulOptions,
1387 REGSAM samDesired, PHKEY phkResult)
1389 static RegOpenKeyExW_Proc s_pfn_Reg_Open_Key_Ex_w = NULL;
1390 HMODULE hm_advapi32 = NULL;
1392 if (is_windows_9x () == TRUE)
1393 return ERROR_NOT_SUPPORTED;
1395 if (g_b_init_reg_open_key_ex_w == 0)
1397 g_b_init_reg_open_key_ex_w = 1;
1398 hm_advapi32 = LoadLibrary ("Advapi32.dll");
1399 if (hm_advapi32)
1400 s_pfn_Reg_Open_Key_Ex_w = (RegOpenKeyExW_Proc)
1401 GetProcAddress (hm_advapi32, "RegOpenKeyExW");
1403 if (s_pfn_Reg_Open_Key_Ex_w == NULL)
1404 return ERROR_NOT_SUPPORTED;
1405 return s_pfn_Reg_Open_Key_Ex_w (hkey, lpSubKey, ulOptions,
1406 samDesired, phkResult);
1409 static LONG WINAPI
1410 reg_query_value_ex_w (HKEY hkey, LPCWSTR lpValueName, LPDWORD lpReserved,
1411 LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData)
1413 static RegQueryValueExW_Proc s_pfn_Reg_Query_Value_Ex_w = NULL;
1414 HMODULE hm_advapi32 = NULL;
1416 if (is_windows_9x () == TRUE)
1417 return ERROR_NOT_SUPPORTED;
1419 if (g_b_init_reg_query_value_ex_w == 0)
1421 g_b_init_reg_query_value_ex_w = 1;
1422 hm_advapi32 = LoadLibrary ("Advapi32.dll");
1423 if (hm_advapi32)
1424 s_pfn_Reg_Query_Value_Ex_w = (RegQueryValueExW_Proc)
1425 GetProcAddress (hm_advapi32, "RegQueryValueExW");
1427 if (s_pfn_Reg_Query_Value_Ex_w == NULL)
1428 return ERROR_NOT_SUPPORTED;
1429 return s_pfn_Reg_Query_Value_Ex_w (hkey, lpValueName, lpReserved,
1430 lpType, lpData, lpcbData);
1433 static DWORD WINAPI
1434 expand_environment_strings_w (LPCWSTR lpSrc, LPWSTR lpDst, DWORD nSize)
1436 static ExpandEnvironmentStringsW_Proc s_pfn_Expand_Environment_Strings_w = NULL;
1437 HMODULE hm_kernel32 = NULL;
1439 if (is_windows_9x () == TRUE)
1440 return ERROR_NOT_SUPPORTED;
1442 if (g_b_init_expand_environment_strings_w == 0)
1444 g_b_init_expand_environment_strings_w = 1;
1445 hm_kernel32 = LoadLibrary ("Kernel32.dll");
1446 if (hm_kernel32)
1447 s_pfn_Expand_Environment_Strings_w = (ExpandEnvironmentStringsW_Proc)
1448 GetProcAddress (hm_kernel32, "ExpandEnvironmentStringsW");
1450 if (s_pfn_Expand_Environment_Strings_w == NULL)
1452 errno = ENOSYS;
1453 return FALSE;
1455 return s_pfn_Expand_Environment_Strings_w (lpSrc, lpDst, nSize);
1460 /* Return 1 if P is a valid pointer to an object of size SIZE. Return
1461 0 if P is NOT a valid pointer. Return -1 if we cannot validate P.
1463 This is called from alloc.c:valid_pointer_p. */
1465 w32_valid_pointer_p (void *p, int size)
1467 SIZE_T done;
1468 HANDLE h = OpenProcess (PROCESS_VM_READ, FALSE, GetCurrentProcessId ());
1470 if (h)
1472 unsigned char *buf = alloca (size);
1473 int retval = ReadProcessMemory (h, p, buf, size, &done);
1475 CloseHandle (h);
1476 return retval;
1478 else
1479 return -1;
1484 /* Here's an overview of how the Windows build supports file names
1485 that cannot be encoded by the current system codepage.
1487 From the POV of Lisp and layers of C code above the functions here,
1488 Emacs on Windows pretends that its file names are encoded in UTF-8;
1489 see encode_file and decode_file on coding.c. Any file name that is
1490 passed as a unibyte string to C functions defined here is assumed
1491 to be in UTF-8 encoding. Any file name returned by functions
1492 defined here must be in UTF-8 encoding, with only a few exceptions
1493 reserved for a couple of special cases. (Be sure to use
1494 MAX_UTF8_PATH for char arrays that store UTF-8 encoded file names,
1495 as they can be much longer than MAX_PATH!)
1497 The UTF-8 encoded file names cannot be passed to system APIs, as
1498 Windows does not support that. Therefore, they are converted
1499 either to UTF-16 or to the ANSI codepage, depending on the value of
1500 w32-unicode-filenames, before calling any system APIs or CRT library
1501 functions. The default value of that variable is determined by the
1502 OS on which Emacs runs: nil on Windows 9X and t otherwise, but the
1503 user can change that default (although I don't see why would she
1504 want to).
1506 The 4 functions defined below, filename_to_utf16, filename_to_ansi,
1507 filename_from_utf16, and filename_from_ansi, are the workhorses of
1508 these conversions. They rely on Windows native APIs
1509 MultiByteToWideChar and WideCharToMultiByte; we cannot use
1510 functions from coding.c here, because they allocate memory, which
1511 is a bad idea on the level of libc, which is what the functions
1512 here emulate. (If you worry about performance due to constant
1513 conversion back and forth from UTF-8 to UTF-16, then don't: first,
1514 it was measured to take only a few microseconds on a not-so-fast
1515 machine, and second, that's exactly what the ANSI APIs we used
1516 before did anyway, because they are just thin wrappers around the
1517 Unicode APIs.)
1519 The variables file-name-coding-system and default-file-name-coding-system
1520 still exist, but are actually used only when a file name needs to
1521 be converted to the ANSI codepage. This happens all the time when
1522 w32-unicode-filenames is nil, but can also happen from time to time
1523 when it is t. Otherwise, these variables have no effect on file-name
1524 encoding when w32-unicode-filenames is t; this is similar to
1525 selection-coding-system.
1527 This arrangement works very well, but it has a few gotchas and
1528 limitations:
1530 . Lisp code that encodes or decodes file names manually should
1531 normally use 'utf-8' as the coding-system on Windows,
1532 disregarding file-name-coding-system. This is a somewhat
1533 unpleasant consequence, but it cannot be avoided. Fortunately,
1534 very few Lisp packages need to do that.
1536 More generally, passing to library functions (e.g., fopen or
1537 opendir) file names already encoded in the ANSI codepage is
1538 explicitly *verboten*, as all those functions, as shadowed and
1539 emulated here, assume they will receive UTF-8 encoded file names.
1541 For the same reasons, no CRT function or Win32 API can be called
1542 directly in Emacs sources, without either converting the file
1543 names from UTF-8 to UTF-16 or ANSI codepage, or going through
1544 some shadowing function defined here.
1546 . Environment variables stored in Vprocess_environment are encoded
1547 in the ANSI codepage, so if getenv/egetenv is used for a variable
1548 whose value is a file name or a list of directories, it needs to
1549 be converted to UTF-8, before it is used as argument to functions
1550 or decoded into a Lisp string.
1552 . File names passed to external libraries, like the image libraries
1553 and GnuTLS, need special handling. These libraries generally
1554 don't support UTF-16 or UTF-8 file names, so they must get file
1555 names encoded in the ANSI codepage. To facilitate using these
1556 libraries with file names that are not encodable in the ANSI
1557 codepage, use the function ansi_encode_filename, which will try
1558 to use the short 8+3 alias of a file name if that file name is
1559 not encodable in the ANSI codepage. See image.c and gnutls.c for
1560 examples of how this should be done.
1562 . Running subprocesses in non-ASCII directories and with non-ASCII
1563 file arguments is limited to the current codepage (even though
1564 Emacs is perfectly capable of finding an executable program file
1565 in a directory whose name cannot be encoded in the current
1566 codepage). This is because the command-line arguments are
1567 encoded _before_ they get to the w32-specific level, and the
1568 encoding is not known in advance (it doesn't have to be the
1569 current ANSI codepage), so w32proc.c functions cannot re-encode
1570 them in UTF-16. This should be fixed, but will also require
1571 changes in cmdproxy. The current limitation is not terribly bad
1572 anyway, since very few, if any, Windows console programs that are
1573 likely to be invoked by Emacs support UTF-16 encoded command
1574 lines.
1576 . For similar reasons, server.el and emacsclient are also limited
1577 to the current ANSI codepage for now.
1579 . Emacs itself can only handle command-line arguments encoded in
1580 the current codepage.
1582 . Turning on w32-unicode-filename on Windows 9X (if it at all
1583 works) requires UNICOWS.DLL, which is thus a requirement even in
1584 non-GUI sessions, something that we previously avoided. */
1588 /* Converting file names from UTF-8 to either UTF-16 or the ANSI
1589 codepage defined by file-name-coding-system. */
1591 /* Current codepage for encoding file names. */
1592 static int file_name_codepage;
1594 /* Initialize the codepage used for decoding file names. This is
1595 needed to undo the value recorded during dumping, which might not
1596 be correct when we run the dumped Emacs. */
1597 void
1598 w32_init_file_name_codepage (void)
1600 file_name_codepage = CP_ACP;
1601 w32_ansi_code_page = CP_ACP;
1604 /* Produce a Windows ANSI codepage suitable for encoding file names.
1605 Return the information about that codepage in CP_INFO. */
1607 codepage_for_filenames (CPINFO *cp_info)
1609 /* A simple cache to avoid calling GetCPInfo every time we need to
1610 encode/decode a file name. The file-name encoding is not
1611 supposed to be changed too frequently, if ever. */
1612 static Lisp_Object last_file_name_encoding;
1613 static CPINFO cp;
1614 Lisp_Object current_encoding;
1616 current_encoding = Vfile_name_coding_system;
1617 if (NILP (current_encoding))
1618 current_encoding = Vdefault_file_name_coding_system;
1620 if (!EQ (last_file_name_encoding, current_encoding)
1621 || NILP (last_file_name_encoding))
1623 /* Default to the current ANSI codepage. */
1624 file_name_codepage = w32_ansi_code_page;
1626 if (!NILP (current_encoding))
1628 char *cpname = SSDATA (SYMBOL_NAME (current_encoding));
1629 char *cp = NULL, *end;
1630 int cpnum;
1632 if (strncmp (cpname, "cp", 2) == 0)
1633 cp = cpname + 2;
1634 else if (strncmp (cpname, "windows-", 8) == 0)
1635 cp = cpname + 8;
1637 if (cp)
1639 end = cp;
1640 cpnum = strtol (cp, &end, 10);
1641 if (cpnum && *end == '\0' && end - cp >= 2)
1642 file_name_codepage = cpnum;
1646 if (!file_name_codepage)
1647 file_name_codepage = CP_ACP; /* CP_ACP = 0, but let's not assume that */
1649 if (!GetCPInfo (file_name_codepage, &cp))
1651 file_name_codepage = CP_ACP;
1652 if (!GetCPInfo (file_name_codepage, &cp))
1653 emacs_abort ();
1656 /* Cache the new value. */
1657 last_file_name_encoding = current_encoding;
1659 if (cp_info)
1660 *cp_info = cp;
1662 return file_name_codepage;
1666 filename_to_utf16 (const char *fn_in, wchar_t *fn_out)
1668 int result = pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags, fn_in,
1669 -1, fn_out, MAX_PATH);
1671 if (!result)
1673 DWORD err = GetLastError ();
1675 switch (err)
1677 case ERROR_INVALID_FLAGS:
1678 case ERROR_INVALID_PARAMETER:
1679 errno = EINVAL;
1680 break;
1681 case ERROR_INSUFFICIENT_BUFFER:
1682 case ERROR_NO_UNICODE_TRANSLATION:
1683 default:
1684 errno = ENOENT;
1685 break;
1687 return -1;
1689 return 0;
1693 filename_from_utf16 (const wchar_t *fn_in, char *fn_out)
1695 int result = pWideCharToMultiByte (CP_UTF8, 0, fn_in, -1,
1696 fn_out, MAX_UTF8_PATH, NULL, NULL);
1698 if (!result)
1700 DWORD err = GetLastError ();
1702 switch (err)
1704 case ERROR_INVALID_FLAGS:
1705 case ERROR_INVALID_PARAMETER:
1706 errno = EINVAL;
1707 break;
1708 case ERROR_INSUFFICIENT_BUFFER:
1709 case ERROR_NO_UNICODE_TRANSLATION:
1710 default:
1711 errno = ENOENT;
1712 break;
1714 return -1;
1716 return 0;
1720 filename_to_ansi (const char *fn_in, char *fn_out)
1722 wchar_t fn_utf16[MAX_PATH];
1724 if (filename_to_utf16 (fn_in, fn_utf16) == 0)
1726 int result;
1727 int codepage = codepage_for_filenames (NULL);
1729 result = pWideCharToMultiByte (codepage, 0, fn_utf16, -1,
1730 fn_out, MAX_PATH, NULL, NULL);
1731 if (!result)
1733 DWORD err = GetLastError ();
1735 switch (err)
1737 case ERROR_INVALID_FLAGS:
1738 case ERROR_INVALID_PARAMETER:
1739 errno = EINVAL;
1740 break;
1741 case ERROR_INSUFFICIENT_BUFFER:
1742 case ERROR_NO_UNICODE_TRANSLATION:
1743 default:
1744 errno = ENOENT;
1745 break;
1747 return -1;
1749 return 0;
1751 return -1;
1755 filename_from_ansi (const char *fn_in, char *fn_out)
1757 wchar_t fn_utf16[MAX_PATH];
1758 int codepage = codepage_for_filenames (NULL);
1759 int result = pMultiByteToWideChar (codepage, multiByteToWideCharFlags, fn_in,
1760 -1, fn_utf16, MAX_PATH);
1762 if (!result)
1764 DWORD err = GetLastError ();
1766 switch (err)
1768 case ERROR_INVALID_FLAGS:
1769 case ERROR_INVALID_PARAMETER:
1770 errno = EINVAL;
1771 break;
1772 case ERROR_INSUFFICIENT_BUFFER:
1773 case ERROR_NO_UNICODE_TRANSLATION:
1774 default:
1775 errno = ENOENT;
1776 break;
1778 return -1;
1780 return filename_from_utf16 (fn_utf16, fn_out);
1785 /* The directory where we started, in UTF-8. */
1786 static char startup_dir[MAX_UTF8_PATH];
1788 /* Get the current working directory. */
1789 char *
1790 getcwd (char *dir, int dirsize)
1792 if (!dirsize)
1794 errno = EINVAL;
1795 return NULL;
1797 if (dirsize <= strlen (startup_dir))
1799 errno = ERANGE;
1800 return NULL;
1802 #if 0
1803 if (GetCurrentDirectory (MAXPATHLEN, dir) > 0)
1804 return dir;
1805 return NULL;
1806 #else
1807 /* Emacs doesn't actually change directory itself, it stays in the
1808 same directory where it was started. */
1809 strcpy (dir, startup_dir);
1810 return dir;
1811 #endif
1814 /* Emulate getloadavg. */
1816 struct load_sample {
1817 time_t sample_time;
1818 ULONGLONG idle;
1819 ULONGLONG kernel;
1820 ULONGLONG user;
1823 /* Number of processors on this machine. */
1824 static unsigned num_of_processors;
1826 /* We maintain 1-sec samples for the last 16 minutes in a circular buffer. */
1827 static struct load_sample samples[16*60];
1828 static int first_idx = -1, last_idx = -1;
1829 static int max_idx = ARRAYELTS (samples);
1831 static int
1832 buf_next (int from)
1834 int next_idx = from + 1;
1836 if (next_idx >= max_idx)
1837 next_idx = 0;
1839 return next_idx;
1842 static int
1843 buf_prev (int from)
1845 int prev_idx = from - 1;
1847 if (prev_idx < 0)
1848 prev_idx = max_idx - 1;
1850 return prev_idx;
1853 static void
1854 sample_system_load (ULONGLONG *idle, ULONGLONG *kernel, ULONGLONG *user)
1856 SYSTEM_INFO sysinfo;
1857 FILETIME ft_idle, ft_user, ft_kernel;
1859 /* Initialize the number of processors on this machine. */
1860 if (num_of_processors <= 0)
1862 get_native_system_info (&sysinfo);
1863 num_of_processors = sysinfo.dwNumberOfProcessors;
1864 if (num_of_processors <= 0)
1866 GetSystemInfo (&sysinfo);
1867 num_of_processors = sysinfo.dwNumberOfProcessors;
1869 if (num_of_processors <= 0)
1870 num_of_processors = 1;
1873 /* TODO: Take into account threads that are ready to run, by
1874 sampling the "\System\Processor Queue Length" performance
1875 counter. The code below accounts only for threads that are
1876 actually running. */
1878 if (get_system_times (&ft_idle, &ft_kernel, &ft_user))
1880 ULARGE_INTEGER uidle, ukernel, uuser;
1882 memcpy (&uidle, &ft_idle, sizeof (ft_idle));
1883 memcpy (&ukernel, &ft_kernel, sizeof (ft_kernel));
1884 memcpy (&uuser, &ft_user, sizeof (ft_user));
1885 *idle = uidle.QuadPart;
1886 *kernel = ukernel.QuadPart;
1887 *user = uuser.QuadPart;
1889 else
1891 *idle = 0;
1892 *kernel = 0;
1893 *user = 0;
1897 /* Produce the load average for a given time interval, using the
1898 samples in the samples[] array. WHICH can be 0, 1, or 2, meaning
1899 1-minute, 5-minute, or 15-minute average, respectively. */
1900 static double
1901 getavg (int which)
1903 double retval = -1.0;
1904 double tdiff;
1905 int idx;
1906 double span = (which == 0 ? 1.0 : (which == 1 ? 5.0 : 15.0)) * 60;
1907 time_t now = samples[last_idx].sample_time;
1909 if (first_idx != last_idx)
1911 for (idx = buf_prev (last_idx); ; idx = buf_prev (idx))
1913 tdiff = difftime (now, samples[idx].sample_time);
1914 if (tdiff >= span - 2*DBL_EPSILON*now)
1916 long double sys =
1917 samples[last_idx].kernel + samples[last_idx].user
1918 - (samples[idx].kernel + samples[idx].user);
1919 long double idl = samples[last_idx].idle - samples[idx].idle;
1921 retval = (1.0 - idl / sys) * num_of_processors;
1922 break;
1924 if (idx == first_idx)
1925 break;
1929 return retval;
1933 getloadavg (double loadavg[], int nelem)
1935 int elem;
1936 ULONGLONG idle, kernel, user;
1937 time_t now = time (NULL);
1939 /* If system time jumped back for some reason, delete all samples
1940 whose time is later than the current wall-clock time. This
1941 prevents load average figures from becoming frozen for prolonged
1942 periods of time, when system time is reset backwards. */
1943 if (last_idx >= 0)
1945 while (difftime (now, samples[last_idx].sample_time) < -1.0)
1947 if (last_idx == first_idx)
1949 first_idx = last_idx = -1;
1950 break;
1952 last_idx = buf_prev (last_idx);
1956 /* Store another sample. We ignore samples that are less than 1 sec
1957 apart. */
1958 if (last_idx < 0
1959 || (difftime (now, samples[last_idx].sample_time)
1960 >= 1.0 - 2*DBL_EPSILON*now))
1962 sample_system_load (&idle, &kernel, &user);
1963 last_idx = buf_next (last_idx);
1964 samples[last_idx].sample_time = now;
1965 samples[last_idx].idle = idle;
1966 samples[last_idx].kernel = kernel;
1967 samples[last_idx].user = user;
1968 /* If the buffer has more that 15 min worth of samples, discard
1969 the old ones. */
1970 if (first_idx == -1)
1971 first_idx = last_idx;
1972 while (first_idx != last_idx
1973 && (difftime (now, samples[first_idx].sample_time)
1974 >= 15.0*60 + 2*DBL_EPSILON*now))
1975 first_idx = buf_next (first_idx);
1978 for (elem = 0; elem < nelem; elem++)
1980 double avg = getavg (elem);
1982 if (avg < 0)
1983 break;
1984 loadavg[elem] = avg;
1987 return elem;
1990 /* Emulate getpwuid, getpwnam and others. */
1992 #define PASSWD_FIELD_SIZE 256
1994 static char dflt_passwd_name[PASSWD_FIELD_SIZE];
1995 static char dflt_passwd_passwd[PASSWD_FIELD_SIZE];
1996 static char dflt_passwd_gecos[PASSWD_FIELD_SIZE];
1997 static char dflt_passwd_dir[MAX_UTF8_PATH];
1998 static char dflt_passwd_shell[MAX_UTF8_PATH];
2000 static struct passwd dflt_passwd =
2002 dflt_passwd_name,
2003 dflt_passwd_passwd,
2007 dflt_passwd_gecos,
2008 dflt_passwd_dir,
2009 dflt_passwd_shell,
2012 static char dflt_group_name[GNLEN+1];
2014 static struct group dflt_group =
2016 /* When group information is not available, we return this as the
2017 group for all files. */
2018 dflt_group_name,
2022 unsigned
2023 getuid (void)
2025 return dflt_passwd.pw_uid;
2028 unsigned
2029 geteuid (void)
2031 /* I could imagine arguing for checking to see whether the user is
2032 in the Administrators group and returning a UID of 0 for that
2033 case, but I don't know how wise that would be in the long run. */
2034 return getuid ();
2037 unsigned
2038 getgid (void)
2040 return dflt_passwd.pw_gid;
2043 unsigned
2044 getegid (void)
2046 return getgid ();
2049 struct passwd *
2050 getpwuid (unsigned uid)
2052 if (uid == dflt_passwd.pw_uid)
2053 return &dflt_passwd;
2054 return NULL;
2057 struct group *
2058 getgrgid (gid_t gid)
2060 return &dflt_group;
2063 struct passwd *
2064 getpwnam (char *name)
2066 struct passwd *pw;
2068 pw = getpwuid (getuid ());
2069 if (!pw)
2070 return pw;
2072 if (xstrcasecmp (name, pw->pw_name))
2073 return NULL;
2075 return pw;
2078 static void
2079 init_user_info (void)
2081 /* Find the user's real name by opening the process token and
2082 looking up the name associated with the user-sid in that token.
2084 Use the relative portion of the identifier authority value from
2085 the user-sid as the user id value (same for group id using the
2086 primary group sid from the process token). */
2088 char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
2089 DWORD ulength = sizeof (uname), dlength = sizeof (domain), needed;
2090 DWORD glength = sizeof (gname);
2091 HANDLE token = NULL;
2092 SID_NAME_USE user_type;
2093 unsigned char *buf = NULL;
2094 DWORD blen = 0;
2095 TOKEN_USER user_token;
2096 TOKEN_PRIMARY_GROUP group_token;
2097 BOOL result;
2099 result = open_process_token (GetCurrentProcess (), TOKEN_QUERY, &token);
2100 if (result)
2102 result = get_token_information (token, TokenUser, NULL, 0, &blen);
2103 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
2105 buf = xmalloc (blen);
2106 result = get_token_information (token, TokenUser,
2107 (LPVOID)buf, blen, &needed);
2108 if (result)
2110 memcpy (&user_token, buf, sizeof (user_token));
2111 result = lookup_account_sid (NULL, user_token.User.Sid,
2112 uname, &ulength,
2113 domain, &dlength, &user_type);
2116 else
2117 result = FALSE;
2119 if (result)
2121 strcpy (dflt_passwd.pw_name, uname);
2122 /* Determine a reasonable uid value. */
2123 if (xstrcasecmp ("administrator", uname) == 0)
2125 dflt_passwd.pw_uid = 500; /* well-known Administrator uid */
2126 dflt_passwd.pw_gid = 513; /* well-known None gid */
2128 else
2130 /* Use the last sub-authority value of the RID, the relative
2131 portion of the SID, as user/group ID. */
2132 dflt_passwd.pw_uid = get_rid (user_token.User.Sid);
2134 /* Get group id and name. */
2135 result = get_token_information (token, TokenPrimaryGroup,
2136 (LPVOID)buf, blen, &needed);
2137 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
2139 buf = xrealloc (buf, blen = needed);
2140 result = get_token_information (token, TokenPrimaryGroup,
2141 (LPVOID)buf, blen, &needed);
2143 if (result)
2145 memcpy (&group_token, buf, sizeof (group_token));
2146 dflt_passwd.pw_gid = get_rid (group_token.PrimaryGroup);
2147 dlength = sizeof (domain);
2148 /* If we can get at the real Primary Group name, use that.
2149 Otherwise, the default group name was already set to
2150 "None" in globals_of_w32. */
2151 if (lookup_account_sid (NULL, group_token.PrimaryGroup,
2152 gname, &glength, NULL, &dlength,
2153 &user_type))
2154 strcpy (dflt_group_name, gname);
2156 else
2157 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
2160 /* If security calls are not supported (presumably because we
2161 are running under Windows 9X), fallback to this: */
2162 else if (GetUserName (uname, &ulength))
2164 strcpy (dflt_passwd.pw_name, uname);
2165 if (xstrcasecmp ("administrator", uname) == 0)
2166 dflt_passwd.pw_uid = 0;
2167 else
2168 dflt_passwd.pw_uid = 123;
2169 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
2171 else
2173 strcpy (dflt_passwd.pw_name, "unknown");
2174 dflt_passwd.pw_uid = 123;
2175 dflt_passwd.pw_gid = 123;
2177 dflt_group.gr_gid = dflt_passwd.pw_gid;
2179 /* Set dir and shell from environment variables. */
2180 if (w32_unicode_filenames)
2182 wchar_t *home = _wgetenv (L"HOME");
2183 wchar_t *shell = _wgetenv (L"SHELL");
2185 /* Ensure HOME and SHELL are defined. */
2186 if (home == NULL)
2187 emacs_abort ();
2188 if (shell == NULL)
2189 emacs_abort ();
2190 filename_from_utf16 (home, dflt_passwd.pw_dir);
2191 filename_from_utf16 (shell, dflt_passwd.pw_shell);
2193 else
2195 char *home = getenv ("HOME");
2196 char *shell = getenv ("SHELL");
2198 if (home == NULL)
2199 emacs_abort ();
2200 if (shell == NULL)
2201 emacs_abort ();
2202 filename_from_ansi (home, dflt_passwd.pw_dir);
2203 filename_from_ansi (shell, dflt_passwd.pw_shell);
2206 xfree (buf);
2207 if (token)
2208 CloseHandle (token);
2211 static HCRYPTPROV w32_crypto_hprov;
2212 static int
2213 w32_init_crypt_random (void)
2215 if (!CryptAcquireContext (&w32_crypto_hprov, NULL, NULL, PROV_RSA_FULL,
2216 CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
2218 DebPrint (("CryptAcquireContext failed with error %x\n",
2219 GetLastError ()));
2220 w32_crypto_hprov = 0;
2221 return -1;
2223 return 0;
2227 w32_init_random (void *buf, ptrdiff_t buflen)
2229 if (!w32_crypto_hprov)
2230 w32_init_crypt_random ();
2231 if (w32_crypto_hprov)
2233 if (CryptGenRandom (w32_crypto_hprov, buflen, (BYTE *)buf))
2234 return 0;
2236 return -1;
2239 /* MS-Windows 'rand' produces separate identical series for each
2240 thread, so we replace it with our version. */
2242 /* Algorithm AS183: An Efficient and Portable Pseudo-random Number
2243 Generator, by B.A. Wichmann, I.D. Hill. AS, v31, No. 2 (1982). */
2244 static int ix = 3172, iy = 9814, iz = 20125;
2245 #define RAND_MAX_X 30269
2246 #define RAND_MAX_Y 30307
2247 #define RAND_MAX_Z 30323
2249 static int
2250 rand_as183 (void)
2252 ix = (171 * ix) % RAND_MAX_X;
2253 iy = (172 * iy) % RAND_MAX_Y;
2254 iz = (170 * iz) % RAND_MAX_Z;
2256 return (ix + iy + iz) & 0x7fff;
2260 random (void)
2262 /* rand_as183 () gives us 15 random bits...hack together 30 bits. */
2263 return ((rand_as183 () << 15) | rand_as183 ());
2266 void
2267 srandom (int seed)
2269 srand (seed);
2270 ix = rand () % RAND_MAX_X;
2271 iy = rand () % RAND_MAX_Y;
2272 iz = rand () % RAND_MAX_Z;
2275 /* Return the maximum length in bytes of a multibyte character
2276 sequence encoded in the current ANSI codepage. This is required to
2277 correctly walk the encoded file names one character at a time. */
2278 static int
2279 max_filename_mbslen (void)
2281 CPINFO cp_info;
2283 codepage_for_filenames (&cp_info);
2284 return cp_info.MaxCharSize;
2287 /* Normalize filename by converting in-place all of its path
2288 separators to the separator specified by PATH_SEP. */
2290 static void
2291 normalize_filename (register char *fp, char path_sep)
2293 char *p2;
2295 /* Always lower-case drive letters a-z, even if the filesystem
2296 preserves case in filenames.
2297 This is so filenames can be compared by string comparison
2298 functions that are case-sensitive. Even case-preserving filesystems
2299 do not distinguish case in drive letters. */
2300 p2 = fp + 1;
2302 if (*p2 == ':' && *fp >= 'A' && *fp <= 'Z')
2304 *fp += 'a' - 'A';
2305 fp += 2;
2308 while (*fp)
2310 if ((*fp == '/' || *fp == '\\') && *fp != path_sep)
2311 *fp = path_sep;
2312 fp++;
2316 /* Destructively turn backslashes into slashes. */
2317 void
2318 dostounix_filename (register char *p)
2320 normalize_filename (p, '/');
2323 /* Destructively turn slashes into backslashes. */
2324 void
2325 unixtodos_filename (register char *p)
2327 normalize_filename (p, '\\');
2330 /* Remove all CR's that are followed by a LF.
2331 (From msdos.c...probably should figure out a way to share it,
2332 although this code isn't going to ever change.) */
2333 static int
2334 crlf_to_lf (register int n, register char *buf)
2336 unsigned char *np = (unsigned char *)buf;
2337 unsigned char *startp = np;
2338 char *endp = buf + n;
2340 if (n == 0)
2341 return n;
2342 while (buf < endp - 1)
2344 if (*buf == 0x0d)
2346 if (*(++buf) != 0x0a)
2347 *np++ = 0x0d;
2349 else
2350 *np++ = *buf++;
2352 if (buf < endp)
2353 *np++ = *buf++;
2354 return np - startp;
2357 /* Parse the root part of file name, if present. Return length and
2358 optionally store pointer to char after root. */
2359 static int
2360 parse_root (const char * name, const char ** pPath)
2362 const char * start = name;
2364 if (name == NULL)
2365 return 0;
2367 /* find the root name of the volume if given */
2368 if (isalpha (name[0]) && name[1] == ':')
2370 /* skip past drive specifier */
2371 name += 2;
2372 if (IS_DIRECTORY_SEP (name[0]))
2373 name++;
2375 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
2377 int slashes = 2;
2379 name += 2;
2382 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
2383 break;
2384 name++;
2386 while ( *name );
2387 if (IS_DIRECTORY_SEP (name[0]))
2388 name++;
2391 if (pPath)
2392 *pPath = name;
2394 return name - start;
2397 /* Get long base name for name; name is assumed to be absolute. */
2398 static int
2399 get_long_basename (char * name, char * buf, int size)
2401 HANDLE dir_handle = INVALID_HANDLE_VALUE;
2402 char fname_utf8[MAX_UTF8_PATH];
2403 int len = 0;
2404 int cstatus = -1;
2406 /* Must be valid filename, no wild cards or other invalid characters. */
2407 if (strpbrk (name, "*?|<>\""))
2408 return 0;
2410 if (w32_unicode_filenames)
2412 wchar_t fname_utf16[MAX_PATH];
2413 WIN32_FIND_DATAW find_data_wide;
2415 filename_to_utf16 (name, fname_utf16);
2416 dir_handle = FindFirstFileW (fname_utf16, &find_data_wide);
2417 if (dir_handle != INVALID_HANDLE_VALUE)
2418 cstatus = filename_from_utf16 (find_data_wide.cFileName, fname_utf8);
2420 else
2422 char fname_ansi[MAX_PATH];
2423 WIN32_FIND_DATAA find_data_ansi;
2425 filename_to_ansi (name, fname_ansi);
2426 /* If the ANSI name includes ? characters, it is not encodable
2427 in the ANSI codepage. In that case, we deliver the question
2428 marks to the caller; calling FindFirstFileA in this case
2429 could return some unrelated file name in the same
2430 directory. */
2431 if (_mbspbrk (fname_ansi, "?"))
2433 /* Find the basename of fname_ansi. */
2434 char *p = strrchr (fname_ansi, '\\');
2436 if (!p)
2437 p = fname_ansi;
2438 else
2439 p++;
2440 cstatus = filename_from_ansi (p, fname_utf8);
2442 else
2444 dir_handle = FindFirstFileA (fname_ansi, &find_data_ansi);
2445 if (dir_handle != INVALID_HANDLE_VALUE)
2446 cstatus = filename_from_ansi (find_data_ansi.cFileName, fname_utf8);
2450 if (cstatus == 0 && (len = strlen (fname_utf8)) < size)
2451 memcpy (buf, fname_utf8, len + 1);
2452 else
2453 len = 0;
2455 if (dir_handle != INVALID_HANDLE_VALUE)
2456 FindClose (dir_handle);
2458 return len;
2461 /* Get long name for file, if possible (assumed to be absolute). */
2462 BOOL
2463 w32_get_long_filename (const char * name, char * buf, int size)
2465 char * o = buf;
2466 char * p;
2467 const char * q;
2468 char full[ MAX_UTF8_PATH ];
2469 int len;
2471 len = strlen (name);
2472 if (len >= MAX_UTF8_PATH)
2473 return FALSE;
2475 /* Use local copy for destructive modification. */
2476 memcpy (full, name, len+1);
2477 unixtodos_filename (full);
2479 /* Copy root part verbatim. */
2480 len = parse_root (full, (const char **)&p);
2481 memcpy (o, full, len);
2482 o += len;
2483 *o = '\0';
2484 size -= len;
2486 while (p != NULL && *p)
2488 q = p;
2489 p = strchr (q, '\\');
2490 if (p) *p = '\0';
2491 len = get_long_basename (full, o, size);
2492 if (len > 0)
2494 o += len;
2495 size -= len;
2496 if (p != NULL)
2498 *p++ = '\\';
2499 if (size < 2)
2500 return FALSE;
2501 *o++ = '\\';
2502 size--;
2503 *o = '\0';
2506 else
2507 return FALSE;
2510 return TRUE;
2513 unsigned int
2514 w32_get_short_filename (const char * name, char * buf, int size)
2516 if (w32_unicode_filenames)
2518 wchar_t name_utf16[MAX_PATH], short_name[MAX_PATH];
2519 unsigned int retval;
2521 filename_to_utf16 (name, name_utf16);
2522 retval = GetShortPathNameW (name_utf16, short_name, size);
2523 if (retval && retval < size)
2524 filename_from_utf16 (short_name, buf);
2525 return retval;
2527 else
2529 char name_ansi[MAX_PATH];
2531 filename_to_ansi (name, name_ansi);
2532 return GetShortPathNameA (name_ansi, buf, size);
2536 /* Re-encode FILENAME, a UTF-8 encoded unibyte string, using the
2537 MS-Windows ANSI codepage. If FILENAME includes characters not
2538 supported by the ANSI codepage, return the 8+3 alias of FILENAME,
2539 if it exists. This is needed because the w32 build wants to
2540 support file names outside of the system locale, but image
2541 libraries typically don't support wide (a.k.a. "Unicode") APIs
2542 required for that. */
2544 Lisp_Object
2545 ansi_encode_filename (Lisp_Object filename)
2547 Lisp_Object encoded_filename;
2548 char fname[MAX_PATH];
2550 filename_to_ansi (SSDATA (filename), fname);
2551 if (_mbspbrk (fname, "?"))
2553 char shortname[MAX_PATH];
2555 if (w32_get_short_filename (SSDATA (filename), shortname, MAX_PATH))
2557 dostounix_filename (shortname);
2558 encoded_filename = build_string (shortname);
2560 else
2561 encoded_filename = build_unibyte_string (fname);
2563 else
2564 encoded_filename = build_unibyte_string (fname);
2565 return encoded_filename;
2568 static int
2569 is_unc_volume (const char *filename)
2571 const char *ptr = filename;
2573 if (!IS_DIRECTORY_SEP (ptr[0]) || !IS_DIRECTORY_SEP (ptr[1]) || !ptr[2])
2574 return 0;
2576 if (strpbrk (ptr + 2, "*?|<>\"\\/"))
2577 return 0;
2579 return 1;
2582 /* Emulate the Posix unsetenv. */
2584 unsetenv (const char *name)
2586 char *var;
2587 size_t name_len;
2589 if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
2591 errno = EINVAL;
2592 return -1;
2594 name_len = strlen (name);
2595 /* MS docs says an environment variable cannot be longer than 32K. */
2596 if (name_len > 32767)
2598 errno = ENOMEM;
2599 return 0;
2601 /* It is safe to use 'alloca' with 32K size, since the stack is at
2602 least 2MB, and we set it to 8MB in the link command line. */
2603 var = alloca (name_len + 2);
2604 strncpy (var, name, name_len);
2605 var[name_len++] = '=';
2606 var[name_len] = '\0';
2607 return _putenv (var);
2610 /* MS _putenv doesn't support removing a variable when the argument
2611 does not include the '=' character, so we fix that here. */
2613 sys_putenv (char *str)
2615 const char *const name_end = strchr (str, '=');
2617 if (name_end == NULL)
2619 /* Remove the variable from the environment. */
2620 return unsetenv (str);
2623 if (strncmp (str, "TZ=<", 4) == 0)
2625 /* MS-Windows does not support POSIX.1-2001 angle-bracket TZ
2626 abbreviation syntax. Convert to POSIX.1-1988 syntax if possible,
2627 and to the undocumented placeholder "ZZZ" otherwise. */
2628 bool supported_abbr = true;
2629 for (char *p = str + 4; *p; p++)
2631 if (('0' <= *p && *p <= '9') || *p == '-' || *p == '+')
2632 supported_abbr = false;
2633 else if (*p == '>')
2635 ptrdiff_t abbrlen;
2636 if (supported_abbr)
2638 abbrlen = p - (str + 4);
2639 memmove (str + 3, str + 4, abbrlen);
2641 else
2643 abbrlen = 3;
2644 memset (str + 3, 'Z', abbrlen);
2646 memmove (str + 3 + abbrlen, p + 1, strlen (p));
2647 break;
2652 return _putenv (str);
2655 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
2657 LPBYTE
2658 w32_get_resource (const char *key, LPDWORD lpdwtype)
2660 LPBYTE lpvalue;
2661 HKEY hrootkey = NULL;
2662 DWORD cbData;
2664 /* Check both the current user and the local machine to see if
2665 we have any resources. */
2667 if (RegOpenKeyEx (HKEY_CURRENT_USER, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
2669 lpvalue = NULL;
2671 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
2672 && (lpvalue = xmalloc (cbData)) != NULL
2673 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
2675 RegCloseKey (hrootkey);
2676 return (lpvalue);
2679 xfree (lpvalue);
2681 RegCloseKey (hrootkey);
2684 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
2686 lpvalue = NULL;
2688 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
2689 && (lpvalue = xmalloc (cbData)) != NULL
2690 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
2692 RegCloseKey (hrootkey);
2693 return (lpvalue);
2696 xfree (lpvalue);
2698 RegCloseKey (hrootkey);
2701 return (NULL);
2704 /* The argv[] array holds ANSI-encoded strings, and so this function
2705 works with ANS_encoded strings. */
2706 void
2707 init_environment (char ** argv)
2709 static const char * const tempdirs[] = {
2710 "$TMPDIR", "$TEMP", "$TMP", "c:/"
2713 int i;
2715 const int imax = ARRAYELTS (tempdirs);
2717 /* Implementation note: This function explicitly works with ANSI
2718 file names, not with UTF-8 encoded file names. This is because
2719 this function pushes variables into the Emacs's environment, and
2720 the environment variables are always assumed to be in the
2721 locale-specific encoding. Do NOT call any functions that accept
2722 UTF-8 file names from this function! */
2724 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
2725 temporary files and assume "/tmp" if $TMPDIR is unset, which
2726 will break on DOS/Windows. Refuse to work if we cannot find
2727 a directory, not even "c:/", usable for that purpose. */
2728 for (i = 0; i < imax ; i++)
2730 const char *tmp = tempdirs[i];
2732 if (*tmp == '$')
2733 tmp = getenv (tmp + 1);
2734 /* Note that `access' can lie to us if the directory resides on a
2735 read-only filesystem, like CD-ROM or a write-protected floppy.
2736 The only way to be really sure is to actually create a file and
2737 see if it succeeds. But I think that's too much to ask. */
2739 /* MSVCRT's _access crashes with D_OK, so we use our replacement. */
2740 if (tmp && sys_access (tmp, D_OK) == 0)
2742 char * var = alloca (strlen (tmp) + 8);
2743 sprintf (var, "TMPDIR=%s", tmp);
2744 _putenv (strdup (var));
2745 break;
2748 if (i >= imax)
2749 cmd_error_internal
2750 (Fcons (Qerror,
2751 Fcons (build_string ("no usable temporary directories found!!"),
2752 Qnil)),
2753 "While setting TMPDIR: ");
2755 /* Check for environment variables and use registry settings if they
2756 don't exist. Fallback on default values where applicable. */
2758 int i;
2759 LPBYTE lpval;
2760 DWORD dwType;
2761 char locale_name[32];
2762 char default_home[MAX_PATH];
2763 int appdata = 0;
2765 static const struct env_entry
2767 const char * name;
2768 const char * def_value;
2769 } dflt_envvars[] =
2771 /* If the default value is NULL, we will use the value from the
2772 outside environment or the Registry, but will not push the
2773 variable into the Emacs environment if it is defined neither
2774 in the Registry nor in the outside environment. */
2775 {"HOME", "C:/"},
2776 {"PRELOAD_WINSOCK", NULL},
2777 {"emacs_dir", "C:/emacs"},
2778 {"EMACSLOADPATH", NULL},
2779 {"SHELL", "cmdproxy.exe"}, /* perhaps it is somewhere on PATH */
2780 {"EMACSDATA", NULL},
2781 {"EMACSPATH", NULL},
2782 {"INFOPATH", NULL},
2783 {"EMACSDOC", NULL},
2784 {"TERM", "cmd"},
2785 {"LANG", NULL},
2788 #define N_ENV_VARS ARRAYELTS (dflt_envvars)
2790 /* We need to copy dflt_envvars[] and work on the copy because we
2791 don't want the dumped Emacs to inherit the values of
2792 environment variables we saw during dumping (which could be on
2793 a different system). The defaults above must be left intact. */
2794 struct env_entry env_vars[N_ENV_VARS];
2796 for (i = 0; i < N_ENV_VARS; i++)
2797 env_vars[i] = dflt_envvars[i];
2799 /* For backwards compatibility, check if a .emacs file exists in C:/
2800 If not, then we can try to default to the appdata directory under the
2801 user's profile, which is more likely to be writable. */
2802 if (sys_access ("C:/.emacs", F_OK) != 0)
2804 HRESULT profile_result;
2805 /* Dynamically load ShGetFolderPath, as it won't exist on versions
2806 of Windows 95 and NT4 that have not been updated to include
2807 MSIE 5. */
2808 ShGetFolderPath_fn get_folder_path;
2809 get_folder_path = (ShGetFolderPath_fn)
2810 GetProcAddress (GetModuleHandle ("shell32.dll"), "SHGetFolderPathA");
2812 if (get_folder_path != NULL)
2814 profile_result = get_folder_path (NULL, CSIDL_APPDATA, NULL,
2815 0, default_home);
2817 /* If we can't get the appdata dir, revert to old behavior. */
2818 if (profile_result == S_OK)
2820 env_vars[0].def_value = default_home;
2821 appdata = 1;
2826 /* Get default locale info and use it for LANG. */
2827 if (GetLocaleInfo (LOCALE_USER_DEFAULT,
2828 LOCALE_SABBREVLANGNAME | LOCALE_USE_CP_ACP,
2829 locale_name, sizeof (locale_name)))
2831 for (i = 0; i < N_ENV_VARS; i++)
2833 if (strcmp (env_vars[i].name, "LANG") == 0)
2835 env_vars[i].def_value = locale_name;
2836 break;
2841 #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
2843 /* Treat emacs_dir specially: set it unconditionally based on our
2844 location. */
2846 char *p;
2847 char modname[MAX_PATH];
2849 if (!GetModuleFileNameA (NULL, modname, MAX_PATH))
2850 emacs_abort ();
2851 if ((p = _mbsrchr (modname, '\\')) == NULL)
2852 emacs_abort ();
2853 *p = 0;
2855 if ((p = _mbsrchr (modname, '\\'))
2856 /* From bin means installed Emacs, from src means uninstalled. */
2857 && (xstrcasecmp (p, "\\bin") == 0 || xstrcasecmp (p, "\\src") == 0))
2859 char buf[SET_ENV_BUF_SIZE];
2860 int within_build_tree = xstrcasecmp (p, "\\src") == 0;
2862 *p = 0;
2863 for (p = modname; *p; p = CharNext (p))
2864 if (*p == '\\') *p = '/';
2866 _snprintf (buf, sizeof (buf)-1, "emacs_dir=%s", modname);
2867 _putenv (strdup (buf));
2868 /* If we are running from the Posix-like build tree, define
2869 SHELL to point to our own cmdproxy. The loop below will
2870 then disregard PATH_EXEC and the default value. */
2871 if (within_build_tree)
2873 _snprintf (buf, sizeof (buf) - 1,
2874 "SHELL=%s/nt/cmdproxy.exe", modname);
2875 _putenv (strdup (buf));
2880 for (i = 0; i < N_ENV_VARS; i++)
2882 if (!getenv (env_vars[i].name))
2884 int dont_free = 0;
2885 char bufc[SET_ENV_BUF_SIZE];
2887 if ((lpval = w32_get_resource (env_vars[i].name, &dwType)) == NULL
2888 /* Also ignore empty environment variables. */
2889 || *lpval == 0)
2891 xfree (lpval);
2892 dont_free = 1;
2893 if (strcmp (env_vars[i].name, "SHELL") == 0)
2895 /* Look for cmdproxy.exe in every directory in
2896 PATH_EXEC. FIXME: This does not find cmdproxy
2897 in nt/ when we run uninstalled. */
2898 char fname[MAX_PATH];
2899 const char *pstart = PATH_EXEC, *pend;
2901 do {
2902 pend = _mbschr (pstart, ';');
2903 if (!pend)
2904 pend = pstart + strlen (pstart);
2905 /* Be defensive against series of ;;; characters. */
2906 if (pend > pstart)
2908 strncpy (fname, pstart, pend - pstart);
2909 fname[pend - pstart] = '/';
2910 strcpy (&fname[pend - pstart + 1], "cmdproxy.exe");
2911 ExpandEnvironmentStrings ((LPSTR) fname, bufc,
2912 sizeof (bufc));
2913 if (sys_access (bufc, F_OK) == 0)
2915 lpval = bufc;
2916 dwType = REG_SZ;
2917 break;
2920 if (*pend)
2921 pstart = pend + 1;
2922 else
2923 pstart = pend;
2924 if (!*pstart)
2926 /* If not found in any directory, use the
2927 default as the last resort. */
2928 lpval = (char *)env_vars[i].def_value;
2929 dwType = REG_EXPAND_SZ;
2931 } while (*pstart);
2933 else
2935 lpval = (char *)env_vars[i].def_value;
2936 dwType = REG_EXPAND_SZ;
2938 if (strcmp (env_vars[i].name, "HOME") == 0 && !appdata)
2939 Vdelayed_warnings_list
2940 = Fcons
2941 (listn (CONSTYPE_HEAP, 2,
2942 intern ("initialization"), build_string
2943 ("Use of `C:\\.emacs' without defining `HOME'\n"
2944 "in the environment is deprecated, "
2945 "see `Windows HOME' in the Emacs manual.")),
2946 Vdelayed_warnings_list);
2949 if (lpval)
2951 char buf1[SET_ENV_BUF_SIZE], buf2[SET_ENV_BUF_SIZE];
2953 if (dwType == REG_EXPAND_SZ)
2954 ExpandEnvironmentStrings ((LPSTR) lpval, buf1, sizeof (buf1));
2955 else if (dwType == REG_SZ)
2956 strcpy (buf1, (char *)lpval);
2957 if (dwType == REG_EXPAND_SZ || dwType == REG_SZ)
2959 _snprintf (buf2, sizeof (buf2)-1, "%s=%s", env_vars[i].name,
2960 buf1);
2961 _putenv (strdup (buf2));
2964 if (!dont_free)
2965 xfree (lpval);
2971 /* Rebuild system configuration to reflect invoking system. */
2972 Vsystem_configuration = build_string (EMACS_CONFIGURATION);
2974 /* Another special case: on NT, the PATH variable is actually named
2975 "Path" although cmd.exe (perhaps NT itself) arranges for
2976 environment variable lookup and setting to be case insensitive.
2977 However, Emacs assumes a fully case sensitive environment, so we
2978 need to change "Path" to "PATH" to match the expectations of
2979 various elisp packages. We do this by the sneaky method of
2980 modifying the string in the C runtime environ entry.
2982 The same applies to COMSPEC. */
2984 char ** envp;
2985 const char *path = "PATH=";
2986 int path_len = strlen (path);
2987 const char *comspec = "COMSPEC=";
2988 int comspec_len = strlen (comspec);
2990 for (envp = environ; *envp; envp++)
2991 if (_strnicmp (*envp, path, path_len) == 0)
2992 memcpy (*envp, path, path_len);
2993 else if (_strnicmp (*envp, comspec, comspec_len) == 0)
2994 memcpy (*envp, comspec, comspec_len);
2996 /* Make the same modification to `process-environment' which has
2997 already been initialized in set_initial_environment. */
2998 for (Lisp_Object env = Vprocess_environment; CONSP (env); env = XCDR (env))
3000 Lisp_Object entry = XCAR (env);
3001 if (_strnicmp (SDATA (entry), path, path_len) == 0)
3002 for (int i = 0; i < path_len; i++)
3003 SSET (entry, i, path[i]);
3004 else if (_strnicmp (SDATA (entry), comspec, comspec_len) == 0)
3005 for (int i = 0; i < comspec_len; i++)
3006 SSET (entry, i, comspec[i]);
3010 /* Remember the initial working directory for getcwd. */
3011 /* FIXME: Do we need to resolve possible symlinks in startup_dir?
3012 Does it matter anywhere in Emacs? */
3013 if (w32_unicode_filenames)
3015 wchar_t wstartup_dir[MAX_PATH];
3017 if (!GetCurrentDirectoryW (MAX_PATH, wstartup_dir))
3018 emacs_abort ();
3019 filename_from_utf16 (wstartup_dir, startup_dir);
3021 else
3023 char astartup_dir[MAX_PATH];
3025 if (!GetCurrentDirectoryA (MAX_PATH, astartup_dir))
3026 emacs_abort ();
3027 filename_from_ansi (astartup_dir, startup_dir);
3031 static char modname[MAX_PATH];
3033 if (!GetModuleFileNameA (NULL, modname, MAX_PATH))
3034 emacs_abort ();
3035 argv[0] = modname;
3038 /* Determine if there is a middle mouse button, to allow parse_button
3039 to decide whether right mouse events should be mouse-2 or
3040 mouse-3. */
3041 w32_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);
3043 init_user_info ();
3046 /* Called from expand-file-name when default-directory is not a string. */
3048 char *
3049 emacs_root_dir (void)
3051 static char root_dir[MAX_UTF8_PATH];
3052 const char *p;
3054 p = getenv ("emacs_dir");
3055 if (p == NULL)
3056 emacs_abort ();
3057 filename_from_ansi (p, root_dir);
3058 root_dir[parse_root (root_dir, NULL)] = '\0';
3059 dostounix_filename (root_dir);
3060 return root_dir;
3063 /* Emulate fdutimens. */
3065 /* Set the access and modification time stamps of FD (a.k.a. FILE) to be
3066 TIMESPEC[0] and TIMESPEC[1], respectively.
3067 FD must be either negative -- in which case it is ignored --
3068 or a file descriptor that is open on FILE.
3069 If FD is nonnegative, then FILE can be NULL, which means
3070 use just futimes instead of utimes.
3071 If TIMESPEC is null, FAIL.
3072 Return 0 on success, -1 (setting errno) on failure. */
3075 fdutimens (int fd, char const *file, struct timespec const timespec[2])
3077 if (!timespec)
3079 errno = ENOSYS;
3080 return -1;
3082 if (fd < 0 && !file)
3084 errno = EBADF;
3085 return -1;
3087 /* _futime's prototype defines 2nd arg as having the type 'struct
3088 _utimbuf', while utime needs to accept 'struct utimbuf' for
3089 compatibility with Posix. So we need to use 2 different (but
3090 equivalent) types to avoid compiler warnings, sigh. */
3091 if (fd >= 0)
3093 struct _utimbuf _ut;
3095 _ut.actime = timespec[0].tv_sec;
3096 _ut.modtime = timespec[1].tv_sec;
3097 return _futime (fd, &_ut);
3099 else
3101 struct utimbuf ut;
3103 ut.actime = timespec[0].tv_sec;
3104 ut.modtime = timespec[1].tv_sec;
3105 /* Call 'utime', which is implemented below, not the MS library
3106 function, which fails on directories. */
3107 return utime (file, &ut);
3112 /* ------------------------------------------------------------------------- */
3113 /* IO support and wrapper functions for the Windows API. */
3114 /* ------------------------------------------------------------------------- */
3116 /* Place a wrapper around the MSVC version of ctime. It returns NULL
3117 on network directories, so we handle that case here.
3118 (Ulrich Leodolter, 1/11/95). */
3119 char *
3120 sys_ctime (const time_t *t)
3122 char *str = (char *) ctime (t);
3123 return (str ? str : (char *)"Sun Jan 01 00:00:00 1970");
3126 /* Emulate sleep...we could have done this with a define, but that
3127 would necessitate including windows.h in the files that used it.
3128 This is much easier. */
3129 void
3130 sys_sleep (int seconds)
3132 Sleep (seconds * 1000);
3135 /* Internal MSVC functions for low-level descriptor munging */
3136 extern int __cdecl _set_osfhnd (int fd, long h);
3137 extern int __cdecl _free_osfhnd (int fd);
3139 /* parallel array of private info on file handles */
3140 filedesc fd_info [ MAXDESC ];
3142 typedef struct volume_info_data {
3143 struct volume_info_data * next;
3145 /* time when info was obtained */
3146 DWORD timestamp;
3148 /* actual volume info */
3149 char * root_dir;
3150 DWORD serialnum;
3151 DWORD maxcomp;
3152 DWORD flags;
3153 char * name;
3154 char * type;
3155 } volume_info_data;
3157 /* Global referenced by various functions. */
3158 static volume_info_data volume_info;
3160 /* Vector to indicate which drives are local and fixed (for which cached
3161 data never expires). */
3162 static BOOL fixed_drives[26];
3164 /* Consider cached volume information to be stale if older than 10s,
3165 at least for non-local drives. Info for fixed drives is never stale. */
3166 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
3167 #define VOLINFO_STILL_VALID( root_dir, info ) \
3168 ( ( isalpha (root_dir[0]) && \
3169 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
3170 || GetTickCount () - info->timestamp < 10000 )
3172 /* Cache support functions. */
3174 /* Simple linked list with linear search is sufficient. */
3175 static volume_info_data *volume_cache = NULL;
3177 static volume_info_data *
3178 lookup_volume_info (char * root_dir)
3180 volume_info_data * info;
3182 for (info = volume_cache; info; info = info->next)
3183 if (xstrcasecmp (info->root_dir, root_dir) == 0)
3184 break;
3185 return info;
3188 static void
3189 add_volume_info (char * root_dir, volume_info_data * info)
3191 info->root_dir = xstrdup (root_dir);
3192 unixtodos_filename (info->root_dir);
3193 info->next = volume_cache;
3194 volume_cache = info;
3198 /* Wrapper for GetVolumeInformation, which uses caching to avoid
3199 performance penalty (~2ms on 486 for local drives, 7.5ms for local
3200 cdrom drive, ~5-10ms or more for remote drives on LAN). */
3201 static volume_info_data *
3202 GetCachedVolumeInformation (char * root_dir)
3204 volume_info_data * info;
3205 char default_root[ MAX_UTF8_PATH ];
3206 char name[MAX_PATH+1];
3207 char type[MAX_PATH+1];
3209 /* NULL for root_dir means use root from current directory. */
3210 if (root_dir == NULL)
3212 if (w32_unicode_filenames)
3214 wchar_t curdirw[MAX_PATH];
3216 if (GetCurrentDirectoryW (MAX_PATH, curdirw) == 0)
3217 return NULL;
3218 filename_from_utf16 (curdirw, default_root);
3220 else
3222 char curdira[MAX_PATH];
3224 if (GetCurrentDirectoryA (MAX_PATH, curdira) == 0)
3225 return NULL;
3226 filename_from_ansi (curdira, default_root);
3228 parse_root (default_root, (const char **)&root_dir);
3229 *root_dir = 0;
3230 root_dir = default_root;
3233 /* Local fixed drives can be cached permanently. Removable drives
3234 cannot be cached permanently, since the volume name and serial
3235 number (if nothing else) can change. Remote drives should be
3236 treated as if they are removable, since there is no sure way to
3237 tell whether they are or not. Also, the UNC association of drive
3238 letters mapped to remote volumes can be changed at any time (even
3239 by other processes) without notice.
3241 As a compromise, so we can benefit from caching info for remote
3242 volumes, we use a simple expiry mechanism to invalidate cache
3243 entries that are more than ten seconds old. */
3245 #if 0
3246 /* No point doing this, because WNetGetConnection is even slower than
3247 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
3248 GetDriveType is about the only call of this type which does not
3249 involve network access, and so is extremely quick). */
3251 /* Map drive letter to UNC if remote. */
3252 if (isalpha (root_dir[0]) && !fixed[DRIVE_INDEX (root_dir[0])])
3254 char remote_name[ 256 ];
3255 char drive[3] = { root_dir[0], ':' };
3257 if (WNetGetConnection (drive, remote_name, sizeof (remote_name))
3258 == NO_ERROR)
3259 /* do something */ ;
3261 #endif
3263 info = lookup_volume_info (root_dir);
3265 if (info == NULL || ! VOLINFO_STILL_VALID (root_dir, info))
3267 DWORD serialnum;
3268 DWORD maxcomp;
3269 DWORD flags;
3271 /* Info is not cached, or is stale. */
3272 if (w32_unicode_filenames)
3274 wchar_t root_w[MAX_PATH];
3275 wchar_t name_w[MAX_PATH+1];
3276 wchar_t type_w[MAX_PATH+1];
3278 filename_to_utf16 (root_dir, root_w);
3279 if (!GetVolumeInformationW (root_w,
3280 name_w, sizeof (name_w),
3281 &serialnum,
3282 &maxcomp,
3283 &flags,
3284 type_w, sizeof (type_w)))
3285 return NULL;
3286 /* Hmm... not really 100% correct, as these 2 are not file
3287 names... */
3288 filename_from_utf16 (name_w, name);
3289 filename_from_utf16 (type_w, type);
3291 else
3293 char root_a[MAX_PATH];
3294 char name_a[MAX_PATH+1];
3295 char type_a[MAX_PATH+1];
3297 filename_to_ansi (root_dir, root_a);
3298 if (!GetVolumeInformationA (root_a,
3299 name_a, sizeof (name_a),
3300 &serialnum,
3301 &maxcomp,
3302 &flags,
3303 type_a, sizeof (type_a)))
3304 return NULL;
3305 filename_from_ansi (name_a, name);
3306 filename_from_ansi (type_a, type);
3309 /* Cache the volume information for future use, overwriting existing
3310 entry if present. */
3311 if (info == NULL)
3313 info = xmalloc (sizeof (volume_info_data));
3314 add_volume_info (root_dir, info);
3316 else
3318 xfree (info->name);
3319 xfree (info->type);
3322 info->name = xstrdup (name);
3323 unixtodos_filename (info->name);
3324 info->serialnum = serialnum;
3325 info->maxcomp = maxcomp;
3326 info->flags = flags;
3327 info->type = xstrdup (type);
3328 info->timestamp = GetTickCount ();
3331 return info;
3334 /* Get information on the volume where NAME is held; set path pointer to
3335 start of pathname in NAME (past UNC header\volume header if present),
3336 if pPath is non-NULL.
3338 Note: if NAME includes symlinks, the information is for the volume
3339 of the symlink, not of its target. That's because, even though
3340 GetVolumeInformation returns information about the symlink target
3341 of its argument, we only pass the root directory to
3342 GetVolumeInformation, not the full NAME. */
3343 static int
3344 get_volume_info (const char * name, const char ** pPath)
3346 char temp[MAX_UTF8_PATH];
3347 char *rootname = NULL; /* default to current volume */
3348 volume_info_data * info;
3349 int root_len = parse_root (name, pPath);
3351 if (name == NULL)
3352 return FALSE;
3354 /* Copy the root name of the volume, if given. */
3355 if (root_len)
3357 strncpy (temp, name, root_len);
3358 temp[root_len] = '\0';
3359 unixtodos_filename (temp);
3360 rootname = temp;
3363 info = GetCachedVolumeInformation (rootname);
3364 if (info != NULL)
3366 /* Set global referenced by other functions. */
3367 volume_info = *info;
3368 return TRUE;
3370 return FALSE;
3373 /* Determine if volume is FAT format (ie. only supports short 8.3
3374 names); also set path pointer to start of pathname in name, if
3375 pPath is non-NULL. */
3376 static int
3377 is_fat_volume (const char * name, const char ** pPath)
3379 if (get_volume_info (name, pPath))
3380 return (volume_info.maxcomp == 12);
3381 return FALSE;
3384 /* Convert all slashes in a filename to backslashes, and map filename
3385 to a valid 8.3 name if necessary. The result is a pointer to a
3386 static buffer, so CAVEAT EMPTOR! */
3387 const char *map_w32_filename (const char *, const char **);
3389 const char *
3390 map_w32_filename (const char * name, const char ** pPath)
3392 static char shortname[MAX_UTF8_PATH];
3393 char * str = shortname;
3394 char c;
3395 char * path;
3396 const char * save_name = name;
3398 if (strlen (name) >= sizeof (shortname))
3400 /* Return a filename which will cause callers to fail. */
3401 strcpy (shortname, "?");
3402 return shortname;
3405 if (!fatal_error_in_progress /* disable fancy processing during crash */
3406 && is_fat_volume (name, (const char **)&path)) /* truncate to 8.3 */
3408 register int left = 8; /* maximum number of chars in part */
3409 register int extn = 0; /* extension added? */
3410 register int dots = 2; /* maximum number of dots allowed */
3412 while (name < path)
3413 *str++ = *name++; /* skip past UNC header */
3415 while ((c = *name++))
3417 switch ( c )
3419 case ':':
3420 case '\\':
3421 case '/':
3422 *str++ = (c == ':' ? ':' : '\\');
3423 extn = 0; /* reset extension flags */
3424 dots = 2; /* max 2 dots */
3425 left = 8; /* max length 8 for main part */
3426 break;
3427 case '.':
3428 if ( dots )
3430 /* Convert path components of the form .xxx to _xxx,
3431 but leave . and .. as they are. This allows .emacs
3432 to be read as _emacs, for example. */
3434 if (! *name ||
3435 *name == '.' ||
3436 IS_DIRECTORY_SEP (*name))
3438 *str++ = '.';
3439 dots--;
3441 else
3443 *str++ = '_';
3444 left--;
3445 dots = 0;
3448 else if ( !extn )
3450 *str++ = '.';
3451 extn = 1; /* we've got an extension */
3452 left = 3; /* 3 chars in extension */
3454 else
3456 /* any embedded dots after the first are converted to _ */
3457 *str++ = '_';
3459 break;
3460 case '~':
3461 case '#': /* don't lose these, they're important */
3462 if ( ! left )
3463 str[-1] = c; /* replace last character of part */
3464 /* FALLTHRU */
3465 FALLTHROUGH;
3466 default:
3467 if ( left && 'A' <= c && c <= 'Z' )
3469 *str++ = tolower (c); /* map to lower case (looks nicer) */
3470 left--;
3471 dots = 0; /* started a path component */
3473 break;
3476 *str = '\0';
3478 else
3480 strcpy (shortname, name);
3481 unixtodos_filename (shortname);
3484 if (pPath)
3485 *pPath = shortname + (path - save_name);
3487 return shortname;
3490 static int
3491 is_exec (const char * name)
3493 char * p = strrchr (name, '.');
3494 return
3495 (p != NULL
3496 && (xstrcasecmp (p, ".exe") == 0 ||
3497 xstrcasecmp (p, ".com") == 0 ||
3498 xstrcasecmp (p, ".bat") == 0 ||
3499 xstrcasecmp (p, ".cmd") == 0));
3502 /* Emulate the Unix directory procedures opendir, closedir, and
3503 readdir. We rename them to sys_* names because some versions of
3504 MinGW startup code call opendir and readdir to glob wildcards, and
3505 the code that calls them doesn't grok UTF-8 encoded file names we
3506 produce in dirent->d_name[]. */
3508 struct dirent dir_static; /* simulated directory contents */
3509 static HANDLE dir_find_handle = INVALID_HANDLE_VALUE;
3510 static int dir_is_fat;
3511 static char dir_pathname[MAX_UTF8_PATH];
3512 static WIN32_FIND_DATAW dir_find_data_w;
3513 static WIN32_FIND_DATAA dir_find_data_a;
3514 #define DIR_FIND_DATA_W 1
3515 #define DIR_FIND_DATA_A 2
3516 static int last_dir_find_data = -1;
3518 /* Support shares on a network resource as subdirectories of a read-only
3519 root directory. */
3520 static HANDLE wnet_enum_handle = INVALID_HANDLE_VALUE;
3521 static HANDLE open_unc_volume (const char *);
3522 static void *read_unc_volume (HANDLE, wchar_t *, char *, int);
3523 static void close_unc_volume (HANDLE);
3525 DIR *
3526 sys_opendir (const char *filename)
3528 DIR *dirp;
3530 /* Opening is done by FindFirstFile. However, a read is inherent to
3531 this operation, so we defer the open until read time. */
3533 if (dir_find_handle != INVALID_HANDLE_VALUE)
3534 return NULL;
3535 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
3536 return NULL;
3538 /* Note: We don't support traversal of UNC volumes via symlinks.
3539 Doing so would mean punishing 99.99% of use cases by resolving
3540 all the possible symlinks in FILENAME, recursively. */
3541 if (is_unc_volume (filename))
3543 wnet_enum_handle = open_unc_volume (filename);
3544 if (wnet_enum_handle == INVALID_HANDLE_VALUE)
3545 return NULL;
3548 if (!(dirp = (DIR *) malloc (sizeof (DIR))))
3549 return NULL;
3551 dirp->dd_fd = 0;
3552 dirp->dd_loc = 0;
3553 dirp->dd_size = 0;
3555 strncpy (dir_pathname, map_w32_filename (filename, NULL), MAX_UTF8_PATH - 1);
3556 dir_pathname[MAX_UTF8_PATH - 1] = '\0';
3557 /* Note: We don't support symlinks to file names on FAT volumes.
3558 Doing so would mean punishing 99.99% of use cases by resolving
3559 all the possible symlinks in FILENAME, recursively. */
3560 dir_is_fat = is_fat_volume (filename, NULL);
3562 return dirp;
3565 void
3566 sys_closedir (DIR *dirp)
3568 /* If we have a find-handle open, close it. */
3569 if (dir_find_handle != INVALID_HANDLE_VALUE)
3571 FindClose (dir_find_handle);
3572 dir_find_handle = INVALID_HANDLE_VALUE;
3574 else if (wnet_enum_handle != INVALID_HANDLE_VALUE)
3576 close_unc_volume (wnet_enum_handle);
3577 wnet_enum_handle = INVALID_HANDLE_VALUE;
3579 xfree ((char *) dirp);
3582 struct dirent *
3583 sys_readdir (DIR *dirp)
3585 int downcase = !NILP (Vw32_downcase_file_names);
3587 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
3589 if (!read_unc_volume (wnet_enum_handle,
3590 dir_find_data_w.cFileName,
3591 dir_find_data_a.cFileName,
3592 MAX_PATH))
3593 return NULL;
3595 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
3596 else if (dir_find_handle == INVALID_HANDLE_VALUE)
3598 char filename[MAX_UTF8_PATH];
3599 int ln;
3600 bool last_slash = true;
3602 /* Note: We don't need to worry about dir_pathname being longer
3603 than MAX_UTF8_PATH, as sys_opendir already took care of that
3604 when it called map_w32_filename: that function will put a "?"
3605 in its return value in that case, thus failing all the calls
3606 below. */
3607 strcpy (filename, dir_pathname);
3608 ln = strlen (filename);
3609 if (!IS_DIRECTORY_SEP (filename[ln - 1]))
3610 last_slash = false;
3612 /* Note: No need to resolve symlinks in FILENAME, because
3613 FindFirst opens the directory that is the target of a
3614 symlink. */
3615 if (w32_unicode_filenames)
3617 wchar_t fnw[MAX_PATH + 2];
3619 filename_to_utf16 (filename, fnw);
3620 if (!last_slash)
3621 wcscat (fnw, L"\\");
3622 wcscat (fnw, L"*");
3623 dir_find_handle = FindFirstFileW (fnw, &dir_find_data_w);
3625 else
3627 char fna[MAX_PATH + 2];
3629 filename_to_ansi (filename, fna);
3630 if (!last_slash)
3631 strcat (fna, "\\");
3632 strcat (fna, "*");
3633 /* If FILENAME is not representable by the current ANSI
3634 codepage, we don't want FindFirstFileA to interpret the
3635 '?' characters as a wildcard. */
3636 if (_mbspbrk (fna, "?"))
3637 dir_find_handle = INVALID_HANDLE_VALUE;
3638 else
3639 dir_find_handle = FindFirstFileA (fna, &dir_find_data_a);
3642 if (dir_find_handle == INVALID_HANDLE_VALUE)
3644 /* Any changes in the value of errno here should be in sync
3645 with what directory_files_internal does when it calls
3646 readdir. */
3647 switch (GetLastError ())
3649 /* Windows uses this value when FindFirstFile finds no
3650 files that match the wildcard. This is not supposed
3651 to happen, since our wildcard is "*", but just in
3652 case, if there's some weird empty directory with not
3653 even "." and ".." entries... */
3654 case ERROR_FILE_NOT_FOUND:
3655 errno = 0;
3656 /* FALLTHRU */
3657 default:
3658 break;
3659 case ERROR_ACCESS_DENIED:
3660 case ERROR_NETWORK_ACCESS_DENIED:
3661 errno = EACCES;
3662 break;
3663 case ERROR_PATH_NOT_FOUND:
3664 case ERROR_INVALID_DRIVE:
3665 case ERROR_NOT_READY:
3666 case ERROR_BAD_NETPATH:
3667 case ERROR_BAD_NET_NAME:
3668 errno = ENOENT;
3669 break;
3671 return NULL;
3674 else if (w32_unicode_filenames)
3676 if (!FindNextFileW (dir_find_handle, &dir_find_data_w))
3678 errno = 0;
3679 return NULL;
3682 else
3684 if (!FindNextFileA (dir_find_handle, &dir_find_data_a))
3686 errno = 0;
3687 return NULL;
3691 /* Emacs never uses this value, so don't bother making it match
3692 value returned by stat(). */
3693 dir_static.d_ino = 1;
3695 if (w32_unicode_filenames)
3697 if (downcase || dir_is_fat)
3699 wchar_t tem[MAX_PATH];
3701 wcscpy (tem, dir_find_data_w.cFileName);
3702 CharLowerW (tem);
3703 filename_from_utf16 (tem, dir_static.d_name);
3705 else
3706 filename_from_utf16 (dir_find_data_w.cFileName, dir_static.d_name);
3707 last_dir_find_data = DIR_FIND_DATA_W;
3709 else
3711 char tem[MAX_PATH];
3713 /* If the file name in cFileName[] includes `?' characters, it
3714 means the original file name used characters that cannot be
3715 represented by the current ANSI codepage. To avoid total
3716 lossage, retrieve the short 8+3 alias of the long file
3717 name. */
3718 if (_mbspbrk (dir_find_data_a.cFileName, "?"))
3720 strcpy (tem, dir_find_data_a.cAlternateFileName);
3721 /* 8+3 aliases are returned in all caps, which could break
3722 various alists that look at filenames' extensions. */
3723 downcase = 1;
3725 else if (downcase || dir_is_fat)
3726 strcpy (tem, dir_find_data_a.cFileName);
3727 else
3728 filename_from_ansi (dir_find_data_a.cFileName, dir_static.d_name);
3729 if (downcase || dir_is_fat)
3731 _mbslwr (tem);
3732 filename_from_ansi (tem, dir_static.d_name);
3734 last_dir_find_data = DIR_FIND_DATA_A;
3737 dir_static.d_namlen = strlen (dir_static.d_name);
3738 dir_static.d_reclen = sizeof (struct dirent) - MAX_UTF8_PATH + 3 +
3739 dir_static.d_namlen - dir_static.d_namlen % 4;
3741 return &dir_static;
3744 static HANDLE
3745 open_unc_volume (const char *path)
3747 const char *fn = map_w32_filename (path, NULL);
3748 DWORD result;
3749 HANDLE henum;
3751 if (w32_unicode_filenames)
3753 NETRESOURCEW nrw;
3754 wchar_t fnw[MAX_PATH];
3756 nrw.dwScope = RESOURCE_GLOBALNET;
3757 nrw.dwType = RESOURCETYPE_DISK;
3758 nrw.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
3759 nrw.dwUsage = RESOURCEUSAGE_CONTAINER;
3760 nrw.lpLocalName = NULL;
3761 filename_to_utf16 (fn, fnw);
3762 nrw.lpRemoteName = fnw;
3763 nrw.lpComment = NULL;
3764 nrw.lpProvider = NULL;
3766 result = WNetOpenEnumW (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
3767 RESOURCEUSAGE_CONNECTABLE, &nrw, &henum);
3769 else
3771 NETRESOURCEA nra;
3772 char fna[MAX_PATH];
3774 nra.dwScope = RESOURCE_GLOBALNET;
3775 nra.dwType = RESOURCETYPE_DISK;
3776 nra.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
3777 nra.dwUsage = RESOURCEUSAGE_CONTAINER;
3778 nra.lpLocalName = NULL;
3779 filename_to_ansi (fn, fna);
3780 nra.lpRemoteName = fna;
3781 nra.lpComment = NULL;
3782 nra.lpProvider = NULL;
3784 result = WNetOpenEnumA (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
3785 RESOURCEUSAGE_CONNECTABLE, &nra, &henum);
3787 if (result == NO_ERROR)
3788 return henum;
3789 else
3791 /* Make sure directory_files_internal reports a sensible error. */
3792 errno = ENOENT;
3793 return INVALID_HANDLE_VALUE;
3797 static void *
3798 read_unc_volume (HANDLE henum, wchar_t *fname_w, char *fname_a, int size)
3800 DWORD count;
3801 int result;
3802 char *buffer;
3803 DWORD bufsize = 512;
3804 void *retval;
3806 count = 1;
3807 if (w32_unicode_filenames)
3809 wchar_t *ptrw;
3811 bufsize *= 2;
3812 buffer = alloca (bufsize);
3813 result = WNetEnumResourceW (henum, &count, buffer, &bufsize);
3814 if (result != NO_ERROR)
3815 return NULL;
3816 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
3817 ptrw = ((LPNETRESOURCEW) buffer)->lpRemoteName;
3818 ptrw += 2;
3819 while (*ptrw && *ptrw != L'/' && *ptrw != L'\\') ptrw++;
3820 ptrw++;
3821 wcsncpy (fname_w, ptrw, size);
3822 retval = fname_w;
3824 else
3826 int dbcs_p = max_filename_mbslen () > 1;
3827 char *ptra;
3829 buffer = alloca (bufsize);
3830 result = WNetEnumResourceA (henum, &count, buffer, &bufsize);
3831 if (result != NO_ERROR)
3832 return NULL;
3833 ptra = ((LPNETRESOURCEA) buffer)->lpRemoteName;
3834 ptra += 2;
3835 if (!dbcs_p)
3836 while (*ptra && !IS_DIRECTORY_SEP (*ptra)) ptra++;
3837 else
3839 while (*ptra && !IS_DIRECTORY_SEP (*ptra))
3840 ptra = CharNextExA (file_name_codepage, ptra, 0);
3842 ptra++;
3843 strncpy (fname_a, ptra, size);
3844 retval = fname_a;
3847 return retval;
3850 static void
3851 close_unc_volume (HANDLE henum)
3853 if (henum != INVALID_HANDLE_VALUE)
3854 WNetCloseEnum (henum);
3857 static DWORD
3858 unc_volume_file_attributes (const char *path)
3860 HANDLE henum;
3861 DWORD attrs;
3863 henum = open_unc_volume (path);
3864 if (henum == INVALID_HANDLE_VALUE)
3865 return -1;
3867 attrs = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY;
3869 close_unc_volume (henum);
3871 return attrs;
3874 /* Ensure a network connection is authenticated. */
3875 static void
3876 logon_network_drive (const char *path)
3878 char share[MAX_UTF8_PATH];
3879 int n_slashes;
3880 char drive[4];
3881 UINT drvtype;
3882 char *p;
3883 DWORD val;
3885 if (IS_DIRECTORY_SEP (path[0]) && IS_DIRECTORY_SEP (path[1]))
3886 drvtype = DRIVE_REMOTE;
3887 else if (path[0] == '\0' || path[1] != ':')
3888 drvtype = GetDriveType (NULL);
3889 else
3891 drive[0] = path[0];
3892 drive[1] = ':';
3893 drive[2] = '\\';
3894 drive[3] = '\0';
3895 drvtype = GetDriveType (drive);
3898 /* Only logon to networked drives. */
3899 if (drvtype != DRIVE_REMOTE)
3900 return;
3902 n_slashes = 2;
3903 strncpy (share, path, MAX_UTF8_PATH);
3904 /* Truncate to just server and share name. */
3905 for (p = share + 2; *p && p < share + MAX_UTF8_PATH; p++)
3907 if (IS_DIRECTORY_SEP (*p) && ++n_slashes > 3)
3909 *p = '\0';
3910 break;
3914 if (w32_unicode_filenames)
3916 NETRESOURCEW resourcew;
3917 wchar_t share_w[MAX_PATH];
3919 resourcew.dwScope = RESOURCE_GLOBALNET;
3920 resourcew.dwType = RESOURCETYPE_DISK;
3921 resourcew.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
3922 resourcew.dwUsage = RESOURCEUSAGE_CONTAINER;
3923 resourcew.lpLocalName = NULL;
3924 filename_to_utf16 (share, share_w);
3925 resourcew.lpRemoteName = share_w;
3926 resourcew.lpProvider = NULL;
3928 val = WNetAddConnection2W (&resourcew, NULL, NULL, CONNECT_INTERACTIVE);
3930 else
3932 NETRESOURCEA resourcea;
3933 char share_a[MAX_PATH];
3935 resourcea.dwScope = RESOURCE_GLOBALNET;
3936 resourcea.dwType = RESOURCETYPE_DISK;
3937 resourcea.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
3938 resourcea.dwUsage = RESOURCEUSAGE_CONTAINER;
3939 resourcea.lpLocalName = NULL;
3940 filename_to_ansi (share, share_a);
3941 resourcea.lpRemoteName = share_a;
3942 resourcea.lpProvider = NULL;
3944 val = WNetAddConnection2A (&resourcea, NULL, NULL, CONNECT_INTERACTIVE);
3947 switch (val)
3949 case NO_ERROR:
3950 case ERROR_ALREADY_ASSIGNED:
3951 break;
3952 case ERROR_ACCESS_DENIED:
3953 case ERROR_LOGON_FAILURE:
3954 errno = EACCES;
3955 break;
3956 case ERROR_BUSY:
3957 errno = EAGAIN;
3958 break;
3959 case ERROR_BAD_NET_NAME:
3960 case ERROR_NO_NET_OR_BAD_PATH:
3961 case ERROR_NO_NETWORK:
3962 case ERROR_CANCELLED:
3963 default:
3964 errno = ENOENT;
3965 break;
3969 /* Emulate faccessat(2). */
3971 faccessat (int dirfd, const char * path, int mode, int flags)
3973 DWORD attributes;
3974 char fullname[MAX_UTF8_PATH];
3976 /* Rely on a hack: an open directory is modeled as file descriptor 0,
3977 and its actual file name is stored in dir_pathname by opendir.
3978 This is good enough for the current usage in Emacs, but is fragile. */
3979 if (dirfd != AT_FDCWD
3980 && !(IS_DIRECTORY_SEP (path[0])
3981 || IS_DEVICE_SEP (path[1])))
3983 char lastc = dir_pathname[strlen (dir_pathname) - 1];
3985 if (_snprintf (fullname, sizeof fullname, "%s%s%s",
3986 dir_pathname, IS_DIRECTORY_SEP (lastc) ? "" : "/", path)
3987 < 0)
3989 errno = ENAMETOOLONG;
3990 return -1;
3992 path = fullname;
3995 /* When dired.c calls us with F_OK and a trailing slash, it actually
3996 wants to know whether PATH is a directory. */
3997 if (IS_DIRECTORY_SEP (path[strlen (path) - 1]) && mode == F_OK)
3998 mode |= D_OK;
4000 /* MSVCRT implementation of 'access' doesn't recognize D_OK, and its
4001 newer versions blow up when passed D_OK. */
4002 path = map_w32_filename (path, NULL);
4003 /* If the last element of PATH is a symlink, we need to resolve it
4004 to get the attributes of its target file. Note: any symlinks in
4005 PATH elements other than the last one are transparently resolved
4006 by GetFileAttributes below. */
4007 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0
4008 && (flags & AT_SYMLINK_NOFOLLOW) == 0)
4009 path = chase_symlinks (path);
4011 if (w32_unicode_filenames)
4013 wchar_t path_w[MAX_PATH];
4015 filename_to_utf16 (path, path_w);
4016 attributes = GetFileAttributesW (path_w);
4018 else
4020 char path_a[MAX_PATH];
4022 filename_to_ansi (path, path_a);
4023 attributes = GetFileAttributesA (path_a);
4026 if (attributes == -1)
4028 DWORD w32err = GetLastError ();
4030 switch (w32err)
4032 case ERROR_INVALID_NAME:
4033 case ERROR_BAD_PATHNAME:
4034 if (is_unc_volume (path))
4036 attributes = unc_volume_file_attributes (path);
4037 if (attributes == -1)
4039 errno = EACCES;
4040 return -1;
4042 goto check_attrs;
4044 /* FALLTHROUGH */
4045 FALLTHROUGH;
4046 case ERROR_FILE_NOT_FOUND:
4047 case ERROR_BAD_NETPATH:
4048 errno = ENOENT;
4049 break;
4050 default:
4051 errno = EACCES;
4052 break;
4054 return -1;
4057 check_attrs:
4058 if ((mode & X_OK) != 0
4059 && !(is_exec (path) || (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0))
4061 errno = EACCES;
4062 return -1;
4064 if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0)
4066 errno = EACCES;
4067 return -1;
4069 if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
4071 errno = EACCES;
4072 return -1;
4074 return 0;
4077 /* A special test for DIRNAME being a directory accessible by the
4078 current user. This is needed because the security permissions in
4079 directory's ACLs are not visible in the Posix-style mode bits
4080 returned by 'stat' and in attributes returned by GetFileAttributes.
4081 So a directory would seem like it's readable by the current user,
4082 but will in fact error out with EACCES when they actually try. */
4084 w32_accessible_directory_p (const char *dirname, ptrdiff_t dirlen)
4086 char pattern[MAX_UTF8_PATH];
4087 bool last_slash = dirlen > 0 && IS_DIRECTORY_SEP (dirname[dirlen - 1]);
4088 HANDLE dh;
4090 /* Network volumes need a different reading method. */
4091 if (is_unc_volume (dirname))
4093 void *read_result = NULL;
4094 wchar_t fnw[MAX_PATH];
4095 char fna[MAX_PATH];
4097 dh = open_unc_volume (dirname);
4098 if (dh != INVALID_HANDLE_VALUE)
4100 read_result = read_unc_volume (dh, fnw, fna, MAX_PATH);
4101 close_unc_volume (dh);
4103 /* Treat empty volumes as accessible. */
4104 return read_result != NULL || GetLastError () == ERROR_NO_MORE_ITEMS;
4107 /* Note: map_w32_filename makes sure DIRNAME is not longer than
4108 MAX_UTF8_PATH. */
4109 strcpy (pattern, map_w32_filename (dirname, NULL));
4111 /* Note: No need to resolve symlinks in FILENAME, because FindFirst
4112 opens the directory that is the target of a symlink. */
4113 if (w32_unicode_filenames)
4115 wchar_t pat_w[MAX_PATH + 2];
4116 WIN32_FIND_DATAW dfd_w;
4118 filename_to_utf16 (pattern, pat_w);
4119 if (!last_slash)
4120 wcscat (pat_w, L"\\");
4121 wcscat (pat_w, L"*");
4122 dh = FindFirstFileW (pat_w, &dfd_w);
4124 else
4126 char pat_a[MAX_PATH + 2];
4127 WIN32_FIND_DATAA dfd_a;
4129 filename_to_ansi (pattern, pat_a);
4130 if (!last_slash)
4131 strcpy (pat_a, "\\");
4132 strcat (pat_a, "*");
4133 /* In case DIRNAME cannot be expressed in characters from the
4134 current ANSI codepage. */
4135 if (_mbspbrk (pat_a, "?"))
4136 dh = INVALID_HANDLE_VALUE;
4137 else
4138 dh = FindFirstFileA (pat_a, &dfd_a);
4141 if (dh == INVALID_HANDLE_VALUE)
4142 return 0;
4143 FindClose (dh);
4144 return 1;
4147 /* A version of 'access' to be used locally with file names in
4148 locale-specific encoding. Does not resolve symlinks and does not
4149 support file names on FAT12 and FAT16 volumes, but that's OK, since
4150 we only invoke this function for files inside the Emacs source or
4151 installation tree, on directories (so any symlinks should have the
4152 directory bit set), and on short file names such as "C:/.emacs". */
4153 static int
4154 sys_access (const char *fname, int mode)
4156 char fname_copy[MAX_PATH], *p;
4157 DWORD attributes;
4159 strcpy (fname_copy, fname);
4160 /* Do the equivalent of unixtodos_filename. */
4161 for (p = fname_copy; *p; p = CharNext (p))
4162 if (*p == '/')
4163 *p = '\\';
4165 if ((attributes = GetFileAttributesA (fname_copy)) == -1)
4167 DWORD w32err = GetLastError ();
4169 switch (w32err)
4171 case ERROR_INVALID_NAME:
4172 case ERROR_BAD_PATHNAME:
4173 case ERROR_FILE_NOT_FOUND:
4174 case ERROR_BAD_NETPATH:
4175 errno = ENOENT;
4176 break;
4177 default:
4178 errno = EACCES;
4179 break;
4181 return -1;
4183 if ((mode & X_OK) != 0
4184 && !(is_exec (fname_copy)
4185 || (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0))
4187 errno = EACCES;
4188 return -1;
4190 if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0)
4192 errno = EACCES;
4193 return -1;
4195 if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
4197 errno = EACCES;
4198 return -1;
4200 return 0;
4203 /* Shadow some MSVC runtime functions to map requests for long filenames
4204 to reasonable short names if necessary. This was originally added to
4205 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
4206 long file names. */
4209 sys_chdir (const char * path)
4211 path = map_w32_filename (path, NULL);
4212 if (w32_unicode_filenames)
4214 wchar_t newdir_w[MAX_PATH];
4216 if (filename_to_utf16 (path, newdir_w) == 0)
4217 return _wchdir (newdir_w);
4218 return -1;
4220 else
4222 char newdir_a[MAX_PATH];
4224 if (filename_to_ansi (path, newdir_a) == 0)
4225 return _chdir (newdir_a);
4226 return -1;
4231 sys_chmod (const char * path, int mode)
4233 path = chase_symlinks (map_w32_filename (path, NULL));
4234 if (w32_unicode_filenames)
4236 wchar_t path_w[MAX_PATH];
4238 filename_to_utf16 (path, path_w);
4239 return _wchmod (path_w, mode);
4241 else
4243 char path_a[MAX_PATH];
4245 filename_to_ansi (path, path_a);
4246 return _chmod (path_a, mode);
4251 sys_creat (const char * path, int mode)
4253 path = map_w32_filename (path, NULL);
4254 if (w32_unicode_filenames)
4256 wchar_t path_w[MAX_PATH];
4258 filename_to_utf16 (path, path_w);
4259 return _wcreat (path_w, mode);
4261 else
4263 char path_a[MAX_PATH];
4265 filename_to_ansi (path, path_a);
4266 return _creat (path_a, mode);
4270 FILE *
4271 sys_fopen (const char * path, const char * mode)
4273 int fd;
4274 int oflag;
4275 const char * mode_save = mode;
4277 /* Force all file handles to be non-inheritable. This is necessary to
4278 ensure child processes don't unwittingly inherit handles that might
4279 prevent future file access. */
4281 if (mode[0] == 'r')
4282 oflag = O_RDONLY;
4283 else if (mode[0] == 'w' || mode[0] == 'a')
4284 oflag = O_WRONLY | O_CREAT | O_TRUNC;
4285 else
4286 return NULL;
4288 /* Only do simplistic option parsing. */
4289 while (*++mode)
4290 if (mode[0] == '+')
4292 oflag &= ~(O_RDONLY | O_WRONLY);
4293 oflag |= O_RDWR;
4295 else if (mode[0] == 'b')
4297 oflag &= ~O_TEXT;
4298 oflag |= O_BINARY;
4300 else if (mode[0] == 't')
4302 oflag &= ~O_BINARY;
4303 oflag |= O_TEXT;
4305 else break;
4307 path = map_w32_filename (path, NULL);
4308 if (w32_unicode_filenames)
4310 wchar_t path_w[MAX_PATH];
4312 filename_to_utf16 (path, path_w);
4313 fd = _wopen (path_w, oflag | _O_NOINHERIT, 0644);
4315 else
4317 char path_a[MAX_PATH];
4319 filename_to_ansi (path, path_a);
4320 fd = _open (path_a, oflag | _O_NOINHERIT, 0644);
4322 if (fd < 0)
4323 return NULL;
4325 return _fdopen (fd, mode_save);
4328 /* This only works on NTFS volumes, but is useful to have. */
4330 sys_link (const char * old, const char * new)
4332 HANDLE fileh;
4333 int result = -1;
4334 char oldname[MAX_UTF8_PATH], newname[MAX_UTF8_PATH];
4335 wchar_t oldname_w[MAX_PATH];
4336 char oldname_a[MAX_PATH];
4338 if (old == NULL || new == NULL)
4340 errno = ENOENT;
4341 return -1;
4344 strcpy (oldname, map_w32_filename (old, NULL));
4345 strcpy (newname, map_w32_filename (new, NULL));
4347 if (w32_unicode_filenames)
4349 filename_to_utf16 (oldname, oldname_w);
4350 fileh = CreateFileW (oldname_w, 0, 0, NULL, OPEN_EXISTING,
4351 FILE_FLAG_BACKUP_SEMANTICS, NULL);
4353 else
4355 filename_to_ansi (oldname, oldname_a);
4356 fileh = CreateFileA (oldname_a, 0, 0, NULL, OPEN_EXISTING,
4357 FILE_FLAG_BACKUP_SEMANTICS, NULL);
4359 if (fileh != INVALID_HANDLE_VALUE)
4361 int wlen;
4363 /* Confusingly, the "alternate" stream name field does not apply
4364 when restoring a hard link, and instead contains the actual
4365 stream data for the link (ie. the name of the link to create).
4366 The WIN32_STREAM_ID structure before the cStreamName field is
4367 the stream header, which is then immediately followed by the
4368 stream data. */
4370 struct {
4371 WIN32_STREAM_ID wid;
4372 WCHAR wbuffer[MAX_PATH]; /* extra space for link name */
4373 } data;
4375 /* We used to pass MB_PRECOMPOSED as the 2nd arg here, but MSDN
4376 indicates that flag is unsupported for CP_UTF8, and OTOH says
4377 it is the default anyway. */
4378 wlen = pMultiByteToWideChar (CP_UTF8, 0, newname, -1,
4379 data.wid.cStreamName, MAX_PATH);
4380 if (wlen > 0)
4382 LPVOID context = NULL;
4383 DWORD wbytes = 0;
4385 data.wid.dwStreamId = BACKUP_LINK;
4386 data.wid.dwStreamAttributes = 0;
4387 data.wid.Size.LowPart = wlen * sizeof (WCHAR);
4388 data.wid.Size.HighPart = 0;
4389 data.wid.dwStreamNameSize = 0;
4391 if (BackupWrite (fileh, (LPBYTE)&data,
4392 offsetof (WIN32_STREAM_ID, cStreamName)
4393 + data.wid.Size.LowPart,
4394 &wbytes, FALSE, FALSE, &context)
4395 && BackupWrite (fileh, NULL, 0, &wbytes, TRUE, FALSE, &context))
4397 /* succeeded */
4398 result = 0;
4400 else
4402 DWORD err = GetLastError ();
4403 DWORD attributes;
4405 switch (err)
4407 case ERROR_ACCESS_DENIED:
4408 /* This is what happens when OLDNAME is a directory,
4409 since Windows doesn't support hard links to
4410 directories. Posix says to set errno to EPERM in
4411 that case. */
4412 if (w32_unicode_filenames)
4413 attributes = GetFileAttributesW (oldname_w);
4414 else
4415 attributes = GetFileAttributesA (oldname_a);
4416 if (attributes != -1
4417 && (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
4418 errno = EPERM;
4419 else if (attributes == -1
4420 && is_unc_volume (oldname)
4421 && unc_volume_file_attributes (oldname) != -1)
4422 errno = EPERM;
4423 else
4424 errno = EACCES;
4425 break;
4426 case ERROR_TOO_MANY_LINKS:
4427 errno = EMLINK;
4428 break;
4429 case ERROR_NOT_SAME_DEVICE:
4430 errno = EXDEV;
4431 break;
4432 default:
4433 errno = EINVAL;
4434 break;
4439 CloseHandle (fileh);
4441 else
4442 errno = ENOENT;
4444 return result;
4448 sys_mkdir (const char * path, mode_t mode)
4450 path = map_w32_filename (path, NULL);
4452 if (w32_unicode_filenames)
4454 wchar_t path_w[MAX_PATH];
4456 filename_to_utf16 (path, path_w);
4457 return _wmkdir (path_w);
4459 else
4461 char path_a[MAX_PATH];
4463 filename_to_ansi (path, path_a);
4464 return _mkdir (path_a);
4469 sys_open (const char * path, int oflag, int mode)
4471 const char* mpath = map_w32_filename (path, NULL);
4472 int res = -1;
4474 if (w32_unicode_filenames)
4476 wchar_t mpath_w[MAX_PATH];
4478 filename_to_utf16 (mpath, mpath_w);
4479 /* If possible, try to open file without _O_CREAT, to be able to
4480 write to existing hidden and system files. Force all file
4481 handles to be non-inheritable. */
4482 if ((oflag & (_O_CREAT | _O_EXCL)) != (_O_CREAT | _O_EXCL))
4483 res = _wopen (mpath_w, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
4484 if (res < 0)
4485 res = _wopen (mpath_w, oflag | _O_NOINHERIT, mode);
4487 else
4489 char mpath_a[MAX_PATH];
4491 filename_to_ansi (mpath, mpath_a);
4492 if ((oflag & (_O_CREAT | _O_EXCL)) != (_O_CREAT | _O_EXCL))
4493 res = _open (mpath_a, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
4494 if (res < 0)
4495 res = _open (mpath_a, oflag | _O_NOINHERIT, mode);
4498 return res;
4502 fchmod (int fd, mode_t mode)
4504 return 0;
4508 sys_rename_replace (const char *oldname, const char *newname, BOOL force)
4510 BOOL result;
4511 char temp[MAX_UTF8_PATH], temp_a[MAX_PATH];;
4512 int newname_dev;
4513 int oldname_dev;
4514 bool have_temp_a = false;
4516 /* MoveFile on Windows 95 doesn't correctly change the short file name
4517 alias in a number of circumstances (it is not easy to predict when
4518 just by looking at oldname and newname, unfortunately). In these
4519 cases, renaming through a temporary name avoids the problem.
4521 A second problem on Windows 95 is that renaming through a temp name when
4522 newname is uppercase fails (the final long name ends up in
4523 lowercase, although the short alias might be uppercase) UNLESS the
4524 long temp name is not 8.3.
4526 So, on Windows 95 we always rename through a temp name, and we make sure
4527 the temp name has a long extension to ensure correct renaming. */
4529 strcpy (temp, map_w32_filename (oldname, NULL));
4531 /* volume_info is set indirectly by map_w32_filename. */
4532 oldname_dev = volume_info.serialnum;
4534 if (os_subtype == OS_9X)
4536 char * o;
4537 char * p;
4538 int i = 0;
4539 char oldname_a[MAX_PATH];
4541 oldname = map_w32_filename (oldname, NULL);
4542 filename_to_ansi (oldname, oldname_a);
4543 filename_to_ansi (temp, temp_a);
4544 if ((o = strrchr (oldname_a, '\\')))
4545 o++;
4546 else
4547 o = (char *) oldname_a;
4549 if ((p = strrchr (temp_a, '\\')))
4550 p++;
4551 else
4552 p = temp_a;
4556 /* Force temp name to require a manufactured 8.3 alias - this
4557 seems to make the second rename work properly. */
4558 sprintf (p, "_.%s.%d", o, i);
4559 i++;
4560 result = rename (oldname_a, temp_a);
4562 /* This loop must surely terminate! */
4563 while (result < 0 && errno == EEXIST);
4564 if (result < 0)
4565 return -1;
4566 have_temp_a = true;
4569 /* If FORCE, emulate Unix behavior - newname is deleted if it already exists
4570 (at least if it is a file; don't do this for directories).
4572 Since we mustn't do this if we are just changing the case of the
4573 file name (we would end up deleting the file we are trying to
4574 rename!), we let rename detect if the destination file already
4575 exists - that way we avoid the possible pitfalls of trying to
4576 determine ourselves whether two names really refer to the same
4577 file, which is not always possible in the general case. (Consider
4578 all the permutations of shared or subst'd drives, etc.) */
4580 newname = map_w32_filename (newname, NULL);
4582 /* volume_info is set indirectly by map_w32_filename. */
4583 newname_dev = volume_info.serialnum;
4585 if (w32_unicode_filenames)
4587 wchar_t temp_w[MAX_PATH], newname_w[MAX_PATH];
4589 filename_to_utf16 (temp, temp_w);
4590 filename_to_utf16 (newname, newname_w);
4591 result = _wrename (temp_w, newname_w);
4592 if (result < 0)
4594 DWORD w32err = GetLastError ();
4596 if (errno == EACCES
4597 && newname_dev != oldname_dev)
4599 DWORD attributes;
4600 /* The implementation of `rename' on Windows does not return
4601 errno = EXDEV when you are moving a directory to a
4602 different storage device (ex. logical disk). It returns
4603 EACCES instead. So here we handle such situations and
4604 return EXDEV. */
4605 if ((attributes = GetFileAttributesW (temp_w)) != -1
4606 && (attributes & FILE_ATTRIBUTE_DIRECTORY))
4607 errno = EXDEV;
4609 else if (errno == EEXIST && force)
4611 DWORD attributes_old;
4612 DWORD attributes_new;
4614 if (_wchmod (newname_w, 0666) != 0)
4615 return result;
4616 attributes_old = GetFileAttributesW (temp_w);
4617 attributes_new = GetFileAttributesW (newname_w);
4618 if (attributes_old != -1 && attributes_new != -1
4619 && ((attributes_old & FILE_ATTRIBUTE_DIRECTORY)
4620 != (attributes_new & FILE_ATTRIBUTE_DIRECTORY)))
4622 if ((attributes_old & FILE_ATTRIBUTE_DIRECTORY) != 0)
4623 errno = ENOTDIR;
4624 else
4625 errno = EISDIR;
4626 return -1;
4628 if ((attributes_new & FILE_ATTRIBUTE_DIRECTORY) != 0)
4630 if (_wrmdir (newname_w) != 0)
4631 return result;
4633 else if (_wunlink (newname_w) != 0)
4634 return result;
4635 result = _wrename (temp_w, newname_w);
4637 else if (w32err == ERROR_PRIVILEGE_NOT_HELD
4638 && is_symlink (temp))
4640 /* This is Windows prohibiting the user from creating a
4641 symlink in another place, since that requires
4642 privileges. */
4643 errno = EPERM;
4647 else
4649 char newname_a[MAX_PATH];
4651 if (!have_temp_a)
4652 filename_to_ansi (temp, temp_a);
4653 filename_to_ansi (newname, newname_a);
4654 result = rename (temp_a, newname_a);
4655 if (result < 0)
4657 DWORD w32err = GetLastError ();
4659 if (errno == EACCES
4660 && newname_dev != oldname_dev)
4662 DWORD attributes;
4663 if ((attributes = GetFileAttributesA (temp_a)) != -1
4664 && (attributes & FILE_ATTRIBUTE_DIRECTORY))
4665 errno = EXDEV;
4667 else if (errno == EEXIST && force)
4669 DWORD attributes_old;
4670 DWORD attributes_new;
4672 if (_chmod (newname_a, 0666) != 0)
4673 return result;
4674 attributes_old = GetFileAttributesA (temp_a);
4675 attributes_new = GetFileAttributesA (newname_a);
4676 if (attributes_old != -1 && attributes_new != -1
4677 && ((attributes_old & FILE_ATTRIBUTE_DIRECTORY)
4678 != (attributes_new & FILE_ATTRIBUTE_DIRECTORY)))
4680 if ((attributes_old & FILE_ATTRIBUTE_DIRECTORY) != 0)
4681 errno = ENOTDIR;
4682 else
4683 errno = EISDIR;
4684 return -1;
4686 if ((attributes_new & FILE_ATTRIBUTE_DIRECTORY) != 0)
4688 if (_rmdir (newname_a) != 0)
4689 return result;
4691 else if (_unlink (newname_a) != 0)
4692 return result;
4693 result = rename (temp_a, newname_a);
4695 else if (w32err == ERROR_PRIVILEGE_NOT_HELD
4696 && is_symlink (temp))
4697 errno = EPERM;
4701 return result;
4705 sys_rename (char const *old, char const *new)
4707 return sys_rename_replace (old, new, TRUE);
4711 sys_rmdir (const char * path)
4713 path = map_w32_filename (path, NULL);
4715 if (w32_unicode_filenames)
4717 wchar_t path_w[MAX_PATH];
4719 filename_to_utf16 (path, path_w);
4720 return _wrmdir (path_w);
4722 else
4724 char path_a[MAX_PATH];
4726 filename_to_ansi (path, path_a);
4727 return _rmdir (path_a);
4732 sys_unlink (const char * path)
4734 int rmstatus, e;
4736 path = map_w32_filename (path, NULL);
4738 if (w32_unicode_filenames)
4740 wchar_t path_w[MAX_PATH];
4742 filename_to_utf16 (path, path_w);
4743 /* On Unix, unlink works without write permission. */
4744 _wchmod (path_w, 0666);
4745 rmstatus = _wunlink (path_w);
4746 e = errno;
4747 /* Symlinks to directories can only be deleted by _rmdir;
4748 _unlink returns EACCES. */
4749 if (rmstatus != 0
4750 && errno == EACCES
4751 && (is_symlink (path) & FILE_ATTRIBUTE_DIRECTORY) != 0)
4752 rmstatus = _wrmdir (path_w);
4753 else
4754 errno = e;
4756 else
4758 char path_a[MAX_PATH];
4760 filename_to_ansi (path, path_a);
4761 _chmod (path_a, 0666);
4762 rmstatus = _unlink (path_a);
4763 e = errno;
4764 if (rmstatus != 0
4765 && errno == EACCES
4766 && (is_symlink (path) & FILE_ATTRIBUTE_DIRECTORY) != 0)
4767 rmstatus = _rmdir (path_a);
4768 else
4769 errno = e;
4772 return rmstatus;
4775 static FILETIME utc_base_ft;
4776 static ULONGLONG utc_base; /* In 100ns units */
4777 static int init = 0;
4779 #define FILETIME_TO_U64(result, ft) \
4780 do { \
4781 ULARGE_INTEGER uiTemp; \
4782 uiTemp.LowPart = (ft).dwLowDateTime; \
4783 uiTemp.HighPart = (ft).dwHighDateTime; \
4784 result = uiTemp.QuadPart; \
4785 } while (0)
4787 static void
4788 initialize_utc_base (void)
4790 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
4791 SYSTEMTIME st;
4793 st.wYear = 1970;
4794 st.wMonth = 1;
4795 st.wDay = 1;
4796 st.wHour = 0;
4797 st.wMinute = 0;
4798 st.wSecond = 0;
4799 st.wMilliseconds = 0;
4801 SystemTimeToFileTime (&st, &utc_base_ft);
4802 FILETIME_TO_U64 (utc_base, utc_base_ft);
4805 static time_t
4806 convert_time (FILETIME ft)
4808 ULONGLONG tmp;
4810 if (!init)
4812 initialize_utc_base ();
4813 init = 1;
4816 if (CompareFileTime (&ft, &utc_base_ft) < 0)
4817 return 0;
4819 FILETIME_TO_U64 (tmp, ft);
4820 return (time_t) ((tmp - utc_base) / 10000000L);
4823 static void
4824 convert_from_time_t (time_t time, FILETIME * pft)
4826 ULARGE_INTEGER tmp;
4828 if (!init)
4830 initialize_utc_base ();
4831 init = 1;
4834 /* time in 100ns units since 1-Jan-1601 */
4835 tmp.QuadPart = (ULONGLONG) time * 10000000L + utc_base;
4836 pft->dwHighDateTime = tmp.HighPart;
4837 pft->dwLowDateTime = tmp.LowPart;
4840 static PSECURITY_DESCRIPTOR
4841 get_file_security_desc_by_handle (HANDLE h)
4843 PSECURITY_DESCRIPTOR psd = NULL;
4844 DWORD err;
4845 SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION
4846 | GROUP_SECURITY_INFORMATION /* | DACL_SECURITY_INFORMATION */ ;
4848 err = get_security_info (h, SE_FILE_OBJECT, si,
4849 NULL, NULL, NULL, NULL, &psd);
4850 if (err != ERROR_SUCCESS)
4851 return NULL;
4853 return psd;
4856 static PSECURITY_DESCRIPTOR
4857 get_file_security_desc_by_name (const char *fname)
4859 PSECURITY_DESCRIPTOR psd = NULL;
4860 DWORD sd_len, err;
4861 SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION
4862 | GROUP_SECURITY_INFORMATION /* | DACL_SECURITY_INFORMATION */ ;
4864 if (!get_file_security (fname, si, psd, 0, &sd_len))
4866 err = GetLastError ();
4867 if (err != ERROR_INSUFFICIENT_BUFFER)
4868 return NULL;
4871 psd = xmalloc (sd_len);
4872 if (!get_file_security (fname, si, psd, sd_len, &sd_len))
4874 xfree (psd);
4875 return NULL;
4878 return psd;
4881 static DWORD
4882 get_rid (PSID sid)
4884 unsigned n_subauthorities;
4886 /* Use the last sub-authority value of the RID, the relative
4887 portion of the SID, as user/group ID. */
4888 n_subauthorities = *get_sid_sub_authority_count (sid);
4889 if (n_subauthorities < 1)
4890 return 0; /* the "World" RID */
4891 return *get_sid_sub_authority (sid, n_subauthorities - 1);
4894 /* Caching SID and account values for faster lokup. */
4896 struct w32_id {
4897 unsigned rid;
4898 struct w32_id *next;
4899 char name[GNLEN+1];
4900 unsigned char sid[FLEXIBLE_ARRAY_MEMBER];
4903 static struct w32_id *w32_idlist;
4905 static int
4906 w32_cached_id (PSID sid, unsigned *id, char *name)
4908 struct w32_id *tail, *found;
4910 for (found = NULL, tail = w32_idlist; tail; tail = tail->next)
4912 if (equal_sid ((PSID)tail->sid, sid))
4914 found = tail;
4915 break;
4918 if (found)
4920 *id = found->rid;
4921 strcpy (name, found->name);
4922 return 1;
4924 else
4925 return 0;
4928 static void
4929 w32_add_to_cache (PSID sid, unsigned id, char *name)
4931 DWORD sid_len;
4932 struct w32_id *new_entry;
4934 /* We don't want to leave behind stale cache from when Emacs was
4935 dumped. */
4936 if (initialized)
4938 sid_len = get_length_sid (sid);
4939 new_entry = xmalloc (offsetof (struct w32_id, sid) + sid_len);
4940 if (new_entry)
4942 new_entry->rid = id;
4943 strcpy (new_entry->name, name);
4944 copy_sid (sid_len, (PSID)new_entry->sid, sid);
4945 new_entry->next = w32_idlist;
4946 w32_idlist = new_entry;
4951 #define UID 1
4952 #define GID 2
4954 static int
4955 get_name_and_id (PSECURITY_DESCRIPTOR psd, unsigned *id, char *nm, int what)
4957 PSID sid = NULL;
4958 BOOL dflt;
4959 SID_NAME_USE ignore;
4960 char name[UNLEN+1];
4961 DWORD name_len = sizeof (name);
4962 char domain[1024];
4963 DWORD domain_len = sizeof (domain);
4964 int use_dflt = 0;
4965 int result;
4967 if (what == UID)
4968 result = get_security_descriptor_owner (psd, &sid, &dflt);
4969 else if (what == GID)
4970 result = get_security_descriptor_group (psd, &sid, &dflt);
4971 else
4972 result = 0;
4974 if (!result || !is_valid_sid (sid))
4975 use_dflt = 1;
4976 else if (!w32_cached_id (sid, id, nm))
4978 if (!lookup_account_sid (NULL, sid, name, &name_len,
4979 domain, &domain_len, &ignore)
4980 || name_len > UNLEN+1)
4981 use_dflt = 1;
4982 else
4984 *id = get_rid (sid);
4985 strcpy (nm, name);
4986 w32_add_to_cache (sid, *id, name);
4989 return use_dflt;
4992 static void
4993 get_file_owner_and_group (PSECURITY_DESCRIPTOR psd, struct stat *st)
4995 int dflt_usr = 0, dflt_grp = 0;
4997 if (!psd)
4999 dflt_usr = 1;
5000 dflt_grp = 1;
5002 else
5004 if (get_name_and_id (psd, &st->st_uid, st->st_uname, UID))
5005 dflt_usr = 1;
5006 if (get_name_and_id (psd, &st->st_gid, st->st_gname, GID))
5007 dflt_grp = 1;
5009 /* Consider files to belong to current user/group, if we cannot get
5010 more accurate information. */
5011 if (dflt_usr)
5013 st->st_uid = dflt_passwd.pw_uid;
5014 strcpy (st->st_uname, dflt_passwd.pw_name);
5016 if (dflt_grp)
5018 st->st_gid = dflt_passwd.pw_gid;
5019 strcpy (st->st_gname, dflt_group.gr_name);
5023 /* Return non-zero if NAME is a potentially slow filesystem. */
5024 int is_slow_fs (const char *);
5027 is_slow_fs (const char *name)
5029 char drive_root[4];
5030 UINT devtype;
5032 if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
5033 devtype = DRIVE_REMOTE; /* assume UNC name is remote */
5034 else if (!(strlen (name) >= 2 && IS_DEVICE_SEP (name[1])))
5035 devtype = GetDriveType (NULL); /* use root of current drive */
5036 else
5038 /* GetDriveType needs the root directory of the drive. */
5039 strncpy (drive_root, name, 2);
5040 drive_root[2] = '\\';
5041 drive_root[3] = '\0';
5042 devtype = GetDriveType (drive_root);
5044 return !(devtype == DRIVE_FIXED || devtype == DRIVE_RAMDISK);
5047 /* If this is non-zero, the caller wants accurate information about
5048 file's owner and group, which could be expensive to get. dired.c
5049 uses this flag when needed for the job at hand. */
5050 int w32_stat_get_owner_group;
5052 /* MSVC stat function can't cope with UNC names and has other bugs, so
5053 replace it with our own. This also allows us to calculate consistent
5054 inode values and owner/group without hacks in the main Emacs code,
5055 and support file names encoded in UTF-8. */
5057 static int
5058 stat_worker (const char * path, struct stat * buf, int follow_symlinks)
5060 char *name, *save_name, *r;
5061 WIN32_FIND_DATAW wfd_w;
5062 WIN32_FIND_DATAA wfd_a;
5063 HANDLE fh;
5064 unsigned __int64 fake_inode = 0;
5065 int permission;
5066 int len;
5067 int rootdir = FALSE;
5068 PSECURITY_DESCRIPTOR psd = NULL;
5069 int is_a_symlink = 0;
5070 DWORD file_flags = FILE_FLAG_BACKUP_SEMANTICS;
5071 DWORD access_rights = 0;
5072 DWORD fattrs = 0, serialnum = 0, fs_high = 0, fs_low = 0, nlinks = 1;
5073 FILETIME ctime, atime, wtime;
5074 wchar_t name_w[MAX_PATH];
5075 char name_a[MAX_PATH];
5077 if (path == NULL || buf == NULL)
5079 errno = EFAULT;
5080 return -1;
5083 save_name = name = (char *) map_w32_filename (path, &path);
5084 /* Must be valid filename, no wild cards or other invalid
5085 characters. */
5086 if (strpbrk (name, "*?|<>\""))
5088 errno = ENOENT;
5089 return -1;
5092 len = strlen (name);
5093 /* Allocate 1 extra byte so that we could append a slash to a root
5094 directory, down below. */
5095 name = strcpy (alloca (len + 2), name);
5097 /* Avoid a somewhat costly call to is_symlink if the filesystem
5098 doesn't support symlinks. */
5099 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
5100 is_a_symlink = is_symlink (name);
5102 /* Plan A: Open the file and get all the necessary information via
5103 the resulting handle. This solves several issues in one blow:
5105 . retrieves attributes for the target of a symlink, if needed
5106 . gets attributes of root directories and symlinks pointing to
5107 root directories, thus avoiding the need for special-casing
5108 these and detecting them by examining the file-name format
5109 . retrieves more accurate attributes (e.g., non-zero size for
5110 some directories, esp. directories that are junction points)
5111 . correctly resolves "c:/..", "/.." and similar file names
5112 . avoids run-time penalties for 99% of use cases
5114 Plan A is always tried first, unless the user asked not to (but
5115 if the file is a symlink and we need to follow links, we try Plan
5116 A even if the user asked not to).
5118 If Plan A fails, we go to Plan B (below), where various
5119 potentially expensive techniques must be used to handle "special"
5120 files such as UNC volumes etc. */
5121 if (!(NILP (Vw32_get_true_file_attributes)
5122 || (EQ (Vw32_get_true_file_attributes, Qlocal) && is_slow_fs (name)))
5123 /* Following symlinks requires getting the info by handle. */
5124 || (is_a_symlink && follow_symlinks))
5126 BY_HANDLE_FILE_INFORMATION info;
5128 if (is_a_symlink && !follow_symlinks)
5129 file_flags |= FILE_FLAG_OPEN_REPARSE_POINT;
5130 /* READ_CONTROL access rights are required to get security info
5131 by handle. But if the OS doesn't support security in the
5132 first place, we don't need to try. */
5133 if (is_windows_9x () != TRUE)
5134 access_rights |= READ_CONTROL;
5136 if (w32_unicode_filenames)
5138 filename_to_utf16 (name, name_w);
5139 fh = CreateFileW (name_w, access_rights, 0, NULL, OPEN_EXISTING,
5140 file_flags, NULL);
5141 /* If CreateFile fails with READ_CONTROL, try again with
5142 zero as access rights. */
5143 if (fh == INVALID_HANDLE_VALUE && access_rights)
5144 fh = CreateFileW (name_w, 0, 0, NULL, OPEN_EXISTING,
5145 file_flags, NULL);
5147 else
5149 filename_to_ansi (name, name_a);
5150 fh = CreateFileA (name_a, access_rights, 0, NULL, OPEN_EXISTING,
5151 file_flags, NULL);
5152 if (fh == INVALID_HANDLE_VALUE && access_rights)
5153 fh = CreateFileA (name_a, 0, 0, NULL, OPEN_EXISTING,
5154 file_flags, NULL);
5156 if (fh == INVALID_HANDLE_VALUE)
5157 goto no_true_file_attributes;
5159 /* This is more accurate in terms of getting the correct number
5160 of links, but is quite slow (it is noticeable when Emacs is
5161 making a list of file name completions). */
5162 if (GetFileInformationByHandle (fh, &info))
5164 nlinks = info.nNumberOfLinks;
5165 /* Might as well use file index to fake inode values, but this
5166 is not guaranteed to be unique unless we keep a handle open
5167 all the time (even then there are situations where it is
5168 not unique). Reputedly, there are at most 48 bits of info
5169 (on NTFS, presumably less on FAT). */
5170 fake_inode = info.nFileIndexHigh;
5171 fake_inode <<= 32;
5172 fake_inode += info.nFileIndexLow;
5173 serialnum = info.dwVolumeSerialNumber;
5174 fs_high = info.nFileSizeHigh;
5175 fs_low = info.nFileSizeLow;
5176 ctime = info.ftCreationTime;
5177 atime = info.ftLastAccessTime;
5178 wtime = info.ftLastWriteTime;
5179 fattrs = info.dwFileAttributes;
5181 else
5183 /* We don't go to Plan B here, because it's not clear that
5184 it's a good idea. The only known use case where
5185 CreateFile succeeds, but GetFileInformationByHandle fails
5186 (with ERROR_INVALID_FUNCTION) is for character devices
5187 such as NUL, PRN, etc. For these, switching to Plan B is
5188 a net loss, because we lose the character device
5189 attribute returned by GetFileType below (FindFirstFile
5190 doesn't set that bit in the attributes), and the other
5191 fields don't make sense for character devices anyway.
5192 Emacs doesn't really care for non-file entities in the
5193 context of l?stat, so neither do we. */
5195 /* w32err is assigned so one could put a breakpoint here and
5196 examine its value, when GetFileInformationByHandle
5197 fails. */
5198 DWORD w32err = GetLastError ();
5200 switch (w32err)
5202 case ERROR_FILE_NOT_FOUND: /* can this ever happen? */
5203 errno = ENOENT;
5204 return -1;
5208 /* Test for a symlink before testing for a directory, since
5209 symlinks to directories have the directory bit set, but we
5210 don't want them to appear as directories. */
5211 if (is_a_symlink && !follow_symlinks)
5212 buf->st_mode = S_IFLNK;
5213 else if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
5214 buf->st_mode = S_IFDIR;
5215 else
5217 DWORD ftype = GetFileType (fh);
5219 switch (ftype)
5221 case FILE_TYPE_DISK:
5222 buf->st_mode = S_IFREG;
5223 break;
5224 case FILE_TYPE_PIPE:
5225 buf->st_mode = S_IFIFO;
5226 break;
5227 case FILE_TYPE_CHAR:
5228 case FILE_TYPE_UNKNOWN:
5229 default:
5230 buf->st_mode = S_IFCHR;
5233 /* We produce the fallback owner and group data, based on the
5234 current user that runs Emacs, in the following cases:
5236 . caller didn't request owner and group info
5237 . this is Windows 9X
5238 . getting security by handle failed, and we need to produce
5239 information for the target of a symlink (this is better
5240 than producing a potentially misleading info about the
5241 symlink itself)
5243 If getting security by handle fails, and we don't need to
5244 resolve symlinks, we try getting security by name. */
5245 if (!w32_stat_get_owner_group || is_windows_9x () == TRUE)
5246 get_file_owner_and_group (NULL, buf);
5247 else
5249 psd = get_file_security_desc_by_handle (fh);
5250 if (psd)
5252 get_file_owner_and_group (psd, buf);
5253 LocalFree (psd);
5255 else if (!(is_a_symlink && follow_symlinks))
5257 psd = get_file_security_desc_by_name (name);
5258 get_file_owner_and_group (psd, buf);
5259 xfree (psd);
5261 else
5262 get_file_owner_and_group (NULL, buf);
5264 CloseHandle (fh);
5266 else
5268 no_true_file_attributes:
5269 /* Plan B: Either getting a handle on the file failed, or the
5270 caller explicitly asked us to not bother making this
5271 information more accurate.
5273 Implementation note: In Plan B, we never bother to resolve
5274 symlinks, even if we got here because we tried Plan A and
5275 failed. That's because, even if the caller asked for extra
5276 precision by setting Vw32_get_true_file_attributes to t,
5277 resolving symlinks requires acquiring a file handle to the
5278 symlink, which we already know will fail. And if the user
5279 did not ask for extra precision, resolving symlinks will fly
5280 in the face of that request, since the user then wants the
5281 lightweight version of the code. */
5282 rootdir = (path >= save_name + len - 1
5283 && (IS_DIRECTORY_SEP (*path) || *path == 0));
5285 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
5286 r = IS_DEVICE_SEP (name[1]) ? &name[2] : name;
5287 if (IS_DIRECTORY_SEP (r[0])
5288 && r[1] == '.' && r[2] == '.' && r[3] == '\0')
5289 r[1] = r[2] = '\0';
5291 /* Note: If NAME is a symlink to the root of a UNC volume
5292 (i.e. "\\SERVER"), we will not detect that here, and we will
5293 return data about the symlink as result of FindFirst below.
5294 This is unfortunate, but that marginal use case does not
5295 justify a call to chase_symlinks which would impose a penalty
5296 on all the other use cases. (We get here for symlinks to
5297 roots of UNC volumes because CreateFile above fails for them,
5298 unlike with symlinks to root directories X:\ of drives.) */
5299 if (is_unc_volume (name))
5301 fattrs = unc_volume_file_attributes (name);
5302 if (fattrs == -1)
5303 return -1;
5305 ctime = atime = wtime = utc_base_ft;
5307 else if (rootdir)
5309 /* Make sure root directories end in a slash. */
5310 if (!IS_DIRECTORY_SEP (name[len-1]))
5311 strcpy (name + len, "\\");
5312 if (GetDriveType (name) < 2)
5314 errno = ENOENT;
5315 return -1;
5318 fattrs = FILE_ATTRIBUTE_DIRECTORY;
5319 ctime = atime = wtime = utc_base_ft;
5321 else
5323 int have_wfd = -1;
5325 /* Make sure non-root directories do NOT end in a slash,
5326 otherwise FindFirstFile might fail. */
5327 if (IS_DIRECTORY_SEP (name[len-1]))
5328 name[len - 1] = 0;
5330 /* (This is hacky, but helps when doing file completions on
5331 network drives.) Optimize by using information available from
5332 active readdir if possible. */
5333 len = strlen (dir_pathname);
5334 if (IS_DIRECTORY_SEP (dir_pathname[len-1]))
5335 len--;
5336 if (dir_find_handle != INVALID_HANDLE_VALUE
5337 && last_dir_find_data != -1
5338 && !(is_a_symlink && follow_symlinks)
5339 /* The 2 file-name comparisons below support only ASCII
5340 characters, and will lose (compare not equal) when
5341 the file names include non-ASCII characters that are
5342 the same but for the case. However, doing this
5343 properly involves: (a) converting both file names to
5344 UTF-16, (b) lower-casing both names using CharLowerW,
5345 and (c) comparing the results; this would be quite a
5346 bit slower, whereas Plan B is for users who want
5347 lightweight albeit inaccurate version of 'stat'. */
5348 && c_strncasecmp (save_name, dir_pathname, len) == 0
5349 && IS_DIRECTORY_SEP (name[len])
5350 && xstrcasecmp (name + len + 1, dir_static.d_name) == 0)
5352 have_wfd = last_dir_find_data;
5353 /* This was the last entry returned by readdir. */
5354 if (last_dir_find_data == DIR_FIND_DATA_W)
5355 wfd_w = dir_find_data_w;
5356 else
5357 wfd_a = dir_find_data_a;
5359 else
5361 logon_network_drive (name);
5363 if (w32_unicode_filenames)
5365 filename_to_utf16 (name, name_w);
5366 fh = FindFirstFileW (name_w, &wfd_w);
5367 have_wfd = DIR_FIND_DATA_W;
5369 else
5371 filename_to_ansi (name, name_a);
5372 /* If NAME includes characters not representable by
5373 the current ANSI codepage, filename_to_ansi
5374 usually replaces them with a '?'. We don't want
5375 to let FindFirstFileA interpret those as wildcards,
5376 and "succeed", returning us data from some random
5377 file in the same directory. */
5378 if (_mbspbrk (name_a, "?"))
5379 fh = INVALID_HANDLE_VALUE;
5380 else
5381 fh = FindFirstFileA (name_a, &wfd_a);
5382 have_wfd = DIR_FIND_DATA_A;
5384 if (fh == INVALID_HANDLE_VALUE)
5386 errno = ENOENT;
5387 return -1;
5389 FindClose (fh);
5391 /* Note: if NAME is a symlink, the information we get from
5392 FindFirstFile is for the symlink, not its target. */
5393 if (have_wfd == DIR_FIND_DATA_W)
5395 fattrs = wfd_w.dwFileAttributes;
5396 ctime = wfd_w.ftCreationTime;
5397 atime = wfd_w.ftLastAccessTime;
5398 wtime = wfd_w.ftLastWriteTime;
5399 fs_high = wfd_w.nFileSizeHigh;
5400 fs_low = wfd_w.nFileSizeLow;
5402 else
5404 fattrs = wfd_a.dwFileAttributes;
5405 ctime = wfd_a.ftCreationTime;
5406 atime = wfd_a.ftLastAccessTime;
5407 wtime = wfd_a.ftLastWriteTime;
5408 fs_high = wfd_a.nFileSizeHigh;
5409 fs_low = wfd_a.nFileSizeLow;
5411 fake_inode = 0;
5412 nlinks = 1;
5413 serialnum = volume_info.serialnum;
5415 if (is_a_symlink && !follow_symlinks)
5416 buf->st_mode = S_IFLNK;
5417 else if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
5418 buf->st_mode = S_IFDIR;
5419 else
5420 buf->st_mode = S_IFREG;
5422 get_file_owner_and_group (NULL, buf);
5425 buf->st_ino = fake_inode;
5427 buf->st_dev = serialnum;
5428 buf->st_rdev = serialnum;
5430 buf->st_size = fs_high;
5431 buf->st_size <<= 32;
5432 buf->st_size += fs_low;
5433 buf->st_nlink = nlinks;
5435 /* Convert timestamps to Unix format. */
5436 buf->st_mtime = convert_time (wtime);
5437 buf->st_atime = convert_time (atime);
5438 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
5439 buf->st_ctime = convert_time (ctime);
5440 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
5442 /* determine rwx permissions */
5443 if (is_a_symlink && !follow_symlinks)
5444 permission = S_IREAD | S_IWRITE | S_IEXEC; /* Posix expectations */
5445 else
5447 if (fattrs & FILE_ATTRIBUTE_READONLY)
5448 permission = S_IREAD;
5449 else
5450 permission = S_IREAD | S_IWRITE;
5452 if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
5453 permission |= S_IEXEC;
5454 else if (is_exec (name))
5455 permission |= S_IEXEC;
5458 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
5460 return 0;
5464 stat (const char * path, struct stat * buf)
5466 return stat_worker (path, buf, 1);
5470 lstat (const char * path, struct stat * buf)
5472 return stat_worker (path, buf, 0);
5476 fstatat (int fd, char const *name, struct stat *st, int flags)
5478 /* Rely on a hack: an open directory is modeled as file descriptor 0.
5479 This is good enough for the current usage in Emacs, but is fragile.
5481 FIXME: Add proper support for fdopendir, fstatat, readlinkat.
5482 Gnulib does this and can serve as a model. */
5483 char fullname[MAX_UTF8_PATH];
5485 if (fd != AT_FDCWD)
5487 char lastc = dir_pathname[strlen (dir_pathname) - 1];
5489 if (_snprintf (fullname, sizeof fullname, "%s%s%s",
5490 dir_pathname, IS_DIRECTORY_SEP (lastc) ? "" : "/", name)
5491 < 0)
5493 errno = ENAMETOOLONG;
5494 return -1;
5496 name = fullname;
5499 return stat_worker (name, st, ! (flags & AT_SYMLINK_NOFOLLOW));
5502 /* Provide fstat and utime as well as stat for consistent handling of
5503 file timestamps. */
5505 fstat (int desc, struct stat * buf)
5507 HANDLE fh = (HANDLE) _get_osfhandle (desc);
5508 BY_HANDLE_FILE_INFORMATION info;
5509 unsigned __int64 fake_inode;
5510 int permission;
5512 switch (GetFileType (fh) & ~FILE_TYPE_REMOTE)
5514 case FILE_TYPE_DISK:
5515 buf->st_mode = S_IFREG;
5516 if (!GetFileInformationByHandle (fh, &info))
5518 errno = EACCES;
5519 return -1;
5521 break;
5522 case FILE_TYPE_PIPE:
5523 buf->st_mode = S_IFIFO;
5524 goto non_disk;
5525 case FILE_TYPE_CHAR:
5526 case FILE_TYPE_UNKNOWN:
5527 default:
5528 buf->st_mode = S_IFCHR;
5529 non_disk:
5530 memset (&info, 0, sizeof (info));
5531 info.dwFileAttributes = 0;
5532 info.ftCreationTime = utc_base_ft;
5533 info.ftLastAccessTime = utc_base_ft;
5534 info.ftLastWriteTime = utc_base_ft;
5537 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
5538 buf->st_mode = S_IFDIR;
5540 buf->st_nlink = info.nNumberOfLinks;
5541 /* Might as well use file index to fake inode values, but this
5542 is not guaranteed to be unique unless we keep a handle open
5543 all the time (even then there are situations where it is
5544 not unique). Reputedly, there are at most 48 bits of info
5545 (on NTFS, presumably less on FAT). */
5546 fake_inode = info.nFileIndexHigh;
5547 fake_inode <<= 32;
5548 fake_inode += info.nFileIndexLow;
5550 /* MSVC defines _ino_t to be short; other libc's might not. */
5551 if (sizeof (buf->st_ino) == 2)
5552 buf->st_ino = fake_inode ^ (fake_inode >> 16);
5553 else
5554 buf->st_ino = fake_inode;
5556 /* If the caller so requested, get the true file owner and group.
5557 Otherwise, consider the file to belong to the current user. */
5558 if (!w32_stat_get_owner_group || is_windows_9x () == TRUE)
5559 get_file_owner_and_group (NULL, buf);
5560 else
5562 PSECURITY_DESCRIPTOR psd = NULL;
5564 psd = get_file_security_desc_by_handle (fh);
5565 if (psd)
5567 get_file_owner_and_group (psd, buf);
5568 LocalFree (psd);
5570 else
5571 get_file_owner_and_group (NULL, buf);
5574 buf->st_dev = info.dwVolumeSerialNumber;
5575 buf->st_rdev = info.dwVolumeSerialNumber;
5577 buf->st_size = info.nFileSizeHigh;
5578 buf->st_size <<= 32;
5579 buf->st_size += info.nFileSizeLow;
5581 /* Convert timestamps to Unix format. */
5582 buf->st_mtime = convert_time (info.ftLastWriteTime);
5583 buf->st_atime = convert_time (info.ftLastAccessTime);
5584 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
5585 buf->st_ctime = convert_time (info.ftCreationTime);
5586 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
5588 /* determine rwx permissions */
5589 if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
5590 permission = S_IREAD;
5591 else
5592 permission = S_IREAD | S_IWRITE;
5594 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
5595 permission |= S_IEXEC;
5596 else
5598 #if 0 /* no way of knowing the filename */
5599 char * p = strrchr (name, '.');
5600 if (p != NULL &&
5601 (xstrcasecmp (p, ".exe") == 0 ||
5602 xstrcasecmp (p, ".com") == 0 ||
5603 xstrcasecmp (p, ".bat") == 0 ||
5604 xstrcasecmp (p, ".cmd") == 0))
5605 permission |= S_IEXEC;
5606 #endif
5609 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
5611 return 0;
5614 /* A version of 'utime' which handles directories as well as
5615 files. */
5618 utime (const char *name, struct utimbuf *times)
5620 struct utimbuf deftime;
5621 HANDLE fh;
5622 FILETIME mtime;
5623 FILETIME atime;
5625 if (times == NULL)
5627 deftime.modtime = deftime.actime = time (NULL);
5628 times = &deftime;
5631 if (w32_unicode_filenames)
5633 wchar_t name_utf16[MAX_PATH];
5635 if (filename_to_utf16 (name, name_utf16) != 0)
5636 return -1; /* errno set by filename_to_utf16 */
5638 /* Need write access to set times. */
5639 fh = CreateFileW (name_utf16, FILE_WRITE_ATTRIBUTES,
5640 /* If NAME specifies a directory, FILE_SHARE_DELETE
5641 allows other processes to delete files inside it,
5642 while we have the directory open. */
5643 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
5644 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
5646 else
5648 char name_ansi[MAX_PATH];
5650 if (filename_to_ansi (name, name_ansi) != 0)
5651 return -1; /* errno set by filename_to_ansi */
5653 fh = CreateFileA (name_ansi, FILE_WRITE_ATTRIBUTES,
5654 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
5655 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
5657 if (fh != INVALID_HANDLE_VALUE)
5659 convert_from_time_t (times->actime, &atime);
5660 convert_from_time_t (times->modtime, &mtime);
5661 if (!SetFileTime (fh, NULL, &atime, &mtime))
5663 CloseHandle (fh);
5664 errno = EACCES;
5665 return -1;
5667 CloseHandle (fh);
5669 else
5671 DWORD err = GetLastError ();
5673 switch (err)
5675 case ERROR_FILE_NOT_FOUND:
5676 case ERROR_PATH_NOT_FOUND:
5677 case ERROR_INVALID_DRIVE:
5678 case ERROR_BAD_NETPATH:
5679 case ERROR_DEV_NOT_EXIST:
5680 /* ERROR_INVALID_NAME is the error CreateFile sets when the
5681 file name includes ?s, i.e. translation to ANSI failed. */
5682 case ERROR_INVALID_NAME:
5683 errno = ENOENT;
5684 break;
5685 case ERROR_TOO_MANY_OPEN_FILES:
5686 errno = ENFILE;
5687 break;
5688 case ERROR_ACCESS_DENIED:
5689 case ERROR_SHARING_VIOLATION:
5690 errno = EACCES;
5691 break;
5692 default:
5693 errno = EINVAL;
5694 break;
5696 return -1;
5698 return 0;
5702 sys_umask (int mode)
5704 static int current_mask;
5705 int retval, arg = 0;
5707 /* The only bit we really support is the write bit. Files are
5708 always readable on MS-Windows, and the execute bit does not exist
5709 at all. */
5710 /* FIXME: if the GROUP and OTHER bits are reset, we should use ACLs
5711 to prevent access by other users on NTFS. */
5712 if ((mode & S_IWRITE) != 0)
5713 arg |= S_IWRITE;
5715 retval = _umask (arg);
5716 /* Merge into the return value the bits they've set the last time,
5717 which msvcrt.dll ignores and never returns. Emacs insists on its
5718 notion of mask being identical to what we return. */
5719 retval |= (current_mask & ~S_IWRITE);
5720 current_mask = mode;
5722 return retval;
5726 /* Symlink-related functions. */
5727 #ifndef SYMBOLIC_LINK_FLAG_DIRECTORY
5728 #define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1
5729 #endif
5732 symlink (char const *filename, char const *linkname)
5734 char linkfn[MAX_UTF8_PATH], *tgtfn;
5735 DWORD flags = 0;
5736 int dir_access, filename_ends_in_slash;
5738 /* Diagnostics follows Posix as much as possible. */
5739 if (filename == NULL || linkname == NULL)
5741 errno = EFAULT;
5742 return -1;
5744 if (!*filename)
5746 errno = ENOENT;
5747 return -1;
5749 if (strlen (filename) > MAX_UTF8_PATH || strlen (linkname) > MAX_UTF8_PATH)
5751 errno = ENAMETOOLONG;
5752 return -1;
5755 strcpy (linkfn, map_w32_filename (linkname, NULL));
5756 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) == 0)
5758 errno = EPERM;
5759 return -1;
5762 /* Note: since empty FILENAME was already rejected, we can safely
5763 refer to FILENAME[1]. */
5764 if (!(IS_DIRECTORY_SEP (filename[0]) || IS_DEVICE_SEP (filename[1])))
5766 /* Non-absolute FILENAME is understood as being relative to
5767 LINKNAME's directory. We need to prepend that directory to
5768 FILENAME to get correct results from faccessat below, since
5769 otherwise it will interpret FILENAME relative to the
5770 directory where the Emacs process runs. Note that
5771 make-symbolic-link always makes sure LINKNAME is a fully
5772 expanded file name. */
5773 char tem[MAX_UTF8_PATH];
5774 char *p = linkfn + strlen (linkfn);
5776 while (p > linkfn && !IS_ANY_SEP (p[-1]))
5777 p--;
5778 if (p > linkfn)
5779 strncpy (tem, linkfn, p - linkfn);
5780 strcpy (tem + (p - linkfn), filename);
5781 dir_access = faccessat (AT_FDCWD, tem, D_OK, AT_EACCESS);
5783 else
5784 dir_access = faccessat (AT_FDCWD, filename, D_OK, AT_EACCESS);
5786 /* Since Windows distinguishes between symlinks to directories and
5787 to files, we provide a kludgy feature: if FILENAME doesn't
5788 exist, but ends in a slash, we create a symlink to directory. If
5789 FILENAME exists and is a directory, we always create a symlink to
5790 directory. */
5791 filename_ends_in_slash = IS_DIRECTORY_SEP (filename[strlen (filename) - 1]);
5792 if (dir_access == 0 || filename_ends_in_slash)
5793 flags = SYMBOLIC_LINK_FLAG_DIRECTORY;
5795 tgtfn = (char *)map_w32_filename (filename, NULL);
5796 if (filename_ends_in_slash)
5797 tgtfn[strlen (tgtfn) - 1] = '\0';
5799 errno = 0;
5800 if (!create_symbolic_link (linkfn, tgtfn, flags))
5802 /* ENOSYS is set by create_symbolic_link, when it detects that
5803 the OS doesn't support the CreateSymbolicLink API. */
5804 if (errno != ENOSYS)
5806 DWORD w32err = GetLastError ();
5808 switch (w32err)
5810 /* ERROR_SUCCESS is sometimes returned when LINKFN and
5811 TGTFN point to the same file name, go figure. */
5812 case ERROR_SUCCESS:
5813 case ERROR_FILE_EXISTS:
5814 errno = EEXIST;
5815 break;
5816 case ERROR_ACCESS_DENIED:
5817 errno = EACCES;
5818 break;
5819 case ERROR_FILE_NOT_FOUND:
5820 case ERROR_PATH_NOT_FOUND:
5821 case ERROR_BAD_NETPATH:
5822 case ERROR_INVALID_REPARSE_DATA:
5823 errno = ENOENT;
5824 break;
5825 case ERROR_DIRECTORY:
5826 errno = EISDIR;
5827 break;
5828 case ERROR_PRIVILEGE_NOT_HELD:
5829 case ERROR_NOT_ALL_ASSIGNED:
5830 errno = EPERM;
5831 break;
5832 case ERROR_DISK_FULL:
5833 errno = ENOSPC;
5834 break;
5835 default:
5836 errno = EINVAL;
5837 break;
5840 return -1;
5842 return 0;
5845 /* A quick inexpensive test of whether FILENAME identifies a file that
5846 is a symlink. Returns non-zero if it is, zero otherwise. FILENAME
5847 must already be in the normalized form returned by
5848 map_w32_filename. If the symlink is to a directory, the
5849 FILE_ATTRIBUTE_DIRECTORY bit will be set in the return value.
5851 Note: for repeated operations on many files, it is best to test
5852 whether the underlying volume actually supports symlinks, by
5853 testing the FILE_SUPPORTS_REPARSE_POINTS bit in volume's flags, and
5854 avoid the call to this function if it doesn't. That's because the
5855 call to GetFileAttributes takes a non-negligible time, especially
5856 on non-local or removable filesystems. See stat_worker for an
5857 example of how to do that. */
5858 static int
5859 is_symlink (const char *filename)
5861 DWORD attrs;
5862 wchar_t filename_w[MAX_PATH];
5863 char filename_a[MAX_PATH];
5864 WIN32_FIND_DATAW wfdw;
5865 WIN32_FIND_DATAA wfda;
5866 HANDLE fh;
5867 int attrs_mean_symlink;
5869 if (w32_unicode_filenames)
5871 filename_to_utf16 (filename, filename_w);
5872 attrs = GetFileAttributesW (filename_w);
5874 else
5876 filename_to_ansi (filename, filename_a);
5877 attrs = GetFileAttributesA (filename_a);
5879 if (attrs == -1)
5881 DWORD w32err = GetLastError ();
5883 switch (w32err)
5885 case ERROR_BAD_NETPATH: /* network share, can't be a symlink */
5886 break;
5887 case ERROR_ACCESS_DENIED:
5888 errno = EACCES;
5889 break;
5890 case ERROR_FILE_NOT_FOUND:
5891 case ERROR_PATH_NOT_FOUND:
5892 default:
5893 errno = ENOENT;
5894 break;
5896 return 0;
5898 if ((attrs & FILE_ATTRIBUTE_REPARSE_POINT) == 0)
5899 return 0;
5900 logon_network_drive (filename);
5901 if (w32_unicode_filenames)
5903 fh = FindFirstFileW (filename_w, &wfdw);
5904 attrs_mean_symlink =
5905 (wfdw.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0
5906 && (wfdw.dwReserved0 & IO_REPARSE_TAG_SYMLINK) == IO_REPARSE_TAG_SYMLINK;
5907 if (attrs_mean_symlink)
5908 attrs_mean_symlink |= (wfdw.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
5910 else if (_mbspbrk (filename_a, "?"))
5912 /* filename_to_ansi failed to convert the file name. */
5913 errno = ENOENT;
5914 return 0;
5916 else
5918 fh = FindFirstFileA (filename_a, &wfda);
5919 attrs_mean_symlink =
5920 (wfda.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0
5921 && (wfda.dwReserved0 & IO_REPARSE_TAG_SYMLINK) == IO_REPARSE_TAG_SYMLINK;
5922 if (attrs_mean_symlink)
5923 attrs_mean_symlink |= (wfda.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
5925 if (fh == INVALID_HANDLE_VALUE)
5926 return 0;
5927 FindClose (fh);
5928 return attrs_mean_symlink;
5931 /* If NAME identifies a symbolic link, copy into BUF the file name of
5932 the symlink's target. Copy at most BUF_SIZE bytes, and do NOT
5933 null-terminate the target name, even if it fits. Return the number
5934 of bytes copied, or -1 if NAME is not a symlink or any error was
5935 encountered while resolving it. The file name copied into BUF is
5936 encoded in the current ANSI codepage. */
5937 ssize_t
5938 readlink (const char *name, char *buf, size_t buf_size)
5940 const char *path;
5941 TOKEN_PRIVILEGES privs;
5942 int restore_privs = 0;
5943 HANDLE sh;
5944 ssize_t retval;
5945 char resolved[MAX_UTF8_PATH];
5947 if (name == NULL)
5949 errno = EFAULT;
5950 return -1;
5952 if (!*name)
5954 errno = ENOENT;
5955 return -1;
5958 path = map_w32_filename (name, NULL);
5960 if (strlen (path) > MAX_UTF8_PATH)
5962 errno = ENAMETOOLONG;
5963 return -1;
5966 errno = 0;
5967 if (is_windows_9x () == TRUE
5968 || (volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) == 0
5969 || !is_symlink (path))
5971 if (!errno)
5972 errno = EINVAL; /* not a symlink */
5973 return -1;
5976 /* Done with simple tests, now we're in for some _real_ work. */
5977 if (enable_privilege (SE_BACKUP_NAME, TRUE, &privs))
5978 restore_privs = 1;
5979 /* Implementation note: From here and onward, don't return early,
5980 since that will fail to restore the original set of privileges of
5981 the calling thread. */
5983 retval = -1; /* not too optimistic, are we? */
5985 /* Note: In the next call to CreateFile, we use zero as the 2nd
5986 argument because, when the symlink is a hidden/system file,
5987 e.g. 'C:\Users\All Users', GENERIC_READ fails with
5988 ERROR_ACCESS_DENIED. Zero seems to work just fine, both for file
5989 and directory symlinks. */
5990 if (w32_unicode_filenames)
5992 wchar_t path_w[MAX_PATH];
5994 filename_to_utf16 (path, path_w);
5995 sh = CreateFileW (path_w, 0, 0, NULL, OPEN_EXISTING,
5996 FILE_FLAG_OPEN_REPARSE_POINT
5997 | FILE_FLAG_BACKUP_SEMANTICS,
5998 NULL);
6000 else
6002 char path_a[MAX_PATH];
6004 filename_to_ansi (path, path_a);
6005 sh = CreateFileA (path_a, 0, 0, NULL, OPEN_EXISTING,
6006 FILE_FLAG_OPEN_REPARSE_POINT
6007 | FILE_FLAG_BACKUP_SEMANTICS,
6008 NULL);
6010 if (sh != INVALID_HANDLE_VALUE)
6012 BYTE reparse_buf[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
6013 REPARSE_DATA_BUFFER *reparse_data = (REPARSE_DATA_BUFFER *)&reparse_buf[0];
6014 DWORD retbytes;
6016 if (!DeviceIoControl (sh, FSCTL_GET_REPARSE_POINT, NULL, 0,
6017 reparse_buf, MAXIMUM_REPARSE_DATA_BUFFER_SIZE,
6018 &retbytes, NULL))
6019 errno = EIO;
6020 else if (reparse_data->ReparseTag != IO_REPARSE_TAG_SYMLINK)
6021 errno = EINVAL;
6022 else
6024 /* Copy the link target name, in wide characters, from
6025 reparse_data, then convert it to multibyte encoding in
6026 the current locale's codepage. */
6027 WCHAR *lwname;
6028 size_t lname_size;
6029 USHORT lwname_len =
6030 reparse_data->SymbolicLinkReparseBuffer.PrintNameLength;
6031 WCHAR *lwname_src =
6032 reparse_data->SymbolicLinkReparseBuffer.PathBuffer
6033 + reparse_data->SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(WCHAR);
6034 size_t size_to_copy = buf_size;
6036 /* According to MSDN, PrintNameLength does not include the
6037 terminating null character. */
6038 lwname = alloca ((lwname_len + 1) * sizeof(WCHAR));
6039 memcpy (lwname, lwname_src, lwname_len);
6040 lwname[lwname_len/sizeof(WCHAR)] = 0; /* null-terminate */
6041 filename_from_utf16 (lwname, resolved);
6042 dostounix_filename (resolved);
6043 lname_size = strlen (resolved) + 1;
6044 if (lname_size <= buf_size)
6045 size_to_copy = lname_size;
6046 strncpy (buf, resolved, size_to_copy);
6047 /* Success! */
6048 retval = size_to_copy;
6050 CloseHandle (sh);
6052 else
6054 /* CreateFile failed. */
6055 DWORD w32err2 = GetLastError ();
6057 switch (w32err2)
6059 case ERROR_FILE_NOT_FOUND:
6060 case ERROR_PATH_NOT_FOUND:
6061 errno = ENOENT;
6062 break;
6063 case ERROR_ACCESS_DENIED:
6064 case ERROR_TOO_MANY_OPEN_FILES:
6065 errno = EACCES;
6066 break;
6067 default:
6068 errno = EPERM;
6069 break;
6072 if (restore_privs)
6074 restore_privilege (&privs);
6075 revert_to_self ();
6078 return retval;
6081 ssize_t
6082 readlinkat (int fd, char const *name, char *buffer,
6083 size_t buffer_size)
6085 /* Rely on a hack: an open directory is modeled as file descriptor 0,
6086 as in fstatat. FIXME: Add proper support for readlinkat. */
6087 char fullname[MAX_UTF8_PATH];
6089 if (fd != AT_FDCWD)
6091 if (_snprintf (fullname, sizeof fullname, "%s/%s", dir_pathname, name)
6092 < 0)
6094 errno = ENAMETOOLONG;
6095 return -1;
6097 name = fullname;
6100 return readlink (name, buffer, buffer_size);
6103 /* If FILE is a symlink, return its target (stored in a static
6104 buffer); otherwise return FILE.
6106 This function repeatedly resolves symlinks in the last component of
6107 a chain of symlink file names, as in foo -> bar -> baz -> ...,
6108 until it arrives at a file whose last component is not a symlink,
6109 or some error occurs. It returns the target of the last
6110 successfully resolved symlink in the chain. If it succeeds to
6111 resolve even a single symlink, the value returned is an absolute
6112 file name with backslashes (result of GetFullPathName). By
6113 contrast, if the original FILE is returned, it is unaltered.
6115 Note: This function can set errno even if it succeeds.
6117 Implementation note: we only resolve the last portion ("basename")
6118 of the argument FILE and of each following file in the chain,
6119 disregarding any possible symlinks in its leading directories.
6120 This is because Windows system calls and library functions
6121 transparently resolve symlinks in leading directories and return
6122 correct information, as long as the basename is not a symlink. */
6123 static char *
6124 chase_symlinks (const char *file)
6126 static char target[MAX_UTF8_PATH];
6127 char link[MAX_UTF8_PATH];
6128 wchar_t target_w[MAX_PATH], link_w[MAX_PATH];
6129 char target_a[MAX_PATH], link_a[MAX_PATH];
6130 ssize_t res, link_len;
6131 int loop_count = 0;
6133 if (is_windows_9x () == TRUE || !is_symlink (file))
6134 return (char *)file;
6136 if (w32_unicode_filenames)
6138 wchar_t file_w[MAX_PATH];
6140 filename_to_utf16 (file, file_w);
6141 if (GetFullPathNameW (file_w, MAX_PATH, link_w, NULL) == 0)
6142 return (char *)file;
6143 filename_from_utf16 (link_w, link);
6145 else
6147 char file_a[MAX_PATH];
6149 filename_to_ansi (file, file_a);
6150 if (GetFullPathNameA (file_a, MAX_PATH, link_a, NULL) == 0)
6151 return (char *)file;
6152 filename_from_ansi (link_a, link);
6154 link_len = strlen (link);
6156 target[0] = '\0';
6157 do {
6159 /* Remove trailing slashes, as we want to resolve the last
6160 non-trivial part of the link name. */
6161 while (link_len > 3 && IS_DIRECTORY_SEP (link[link_len-1]))
6162 link[link_len--] = '\0';
6164 res = readlink (link, target, MAX_UTF8_PATH);
6165 if (res > 0)
6167 target[res] = '\0';
6168 if (!(IS_DEVICE_SEP (target[1])
6169 || (IS_DIRECTORY_SEP (target[0]) && IS_DIRECTORY_SEP (target[1]))))
6171 /* Target is relative. Append it to the directory part of
6172 the symlink, then copy the result back to target. */
6173 char *p = link + link_len;
6175 while (p > link && !IS_ANY_SEP (p[-1]))
6176 p--;
6177 strcpy (p, target);
6178 strcpy (target, link);
6180 /* Resolve any "." and ".." to get a fully-qualified file name
6181 in link[] again. */
6182 if (w32_unicode_filenames)
6184 filename_to_utf16 (target, target_w);
6185 link_len = GetFullPathNameW (target_w, MAX_PATH, link_w, NULL);
6186 if (link_len > 0)
6187 filename_from_utf16 (link_w, link);
6189 else
6191 filename_to_ansi (target, target_a);
6192 link_len = GetFullPathNameA (target_a, MAX_PATH, link_a, NULL);
6193 if (link_len > 0)
6194 filename_from_ansi (link_a, link);
6196 link_len = strlen (link);
6198 } while (res > 0 && link_len > 0 && ++loop_count <= 100);
6200 if (loop_count > 100)
6201 errno = ELOOP;
6203 if (target[0] == '\0') /* not a single call to readlink succeeded */
6204 return (char *)file;
6205 return target;
6209 /* Posix ACL emulation. */
6212 acl_valid (acl_t acl)
6214 return is_valid_security_descriptor ((PSECURITY_DESCRIPTOR)acl) ? 0 : -1;
6217 char *
6218 acl_to_text (acl_t acl, ssize_t *size)
6220 LPTSTR str_acl;
6221 SECURITY_INFORMATION flags =
6222 OWNER_SECURITY_INFORMATION |
6223 GROUP_SECURITY_INFORMATION |
6224 DACL_SECURITY_INFORMATION;
6225 char *retval = NULL;
6226 ULONG local_size;
6227 int e = errno;
6229 errno = 0;
6231 if (convert_sd_to_sddl ((PSECURITY_DESCRIPTOR)acl, SDDL_REVISION_1, flags, &str_acl, &local_size))
6233 errno = e;
6234 /* We don't want to mix heaps, so we duplicate the string in our
6235 heap and free the one allocated by the API. */
6236 retval = xstrdup (str_acl);
6237 if (size)
6238 *size = local_size;
6239 LocalFree (str_acl);
6241 else if (errno != ENOTSUP)
6242 errno = EINVAL;
6244 return retval;
6247 acl_t
6248 acl_from_text (const char *acl_str)
6250 PSECURITY_DESCRIPTOR psd, retval = NULL;
6251 ULONG sd_size;
6252 int e = errno;
6254 errno = 0;
6256 if (convert_sddl_to_sd (acl_str, SDDL_REVISION_1, &psd, &sd_size))
6258 errno = e;
6259 retval = xmalloc (sd_size);
6260 memcpy (retval, psd, sd_size);
6261 LocalFree (psd);
6263 else if (errno != ENOTSUP)
6264 errno = EINVAL;
6266 return retval;
6270 acl_free (void *ptr)
6272 xfree (ptr);
6273 return 0;
6276 acl_t
6277 acl_get_file (const char *fname, acl_type_t type)
6279 PSECURITY_DESCRIPTOR psd = NULL;
6280 const char *filename;
6282 if (type == ACL_TYPE_ACCESS)
6284 DWORD sd_len, err;
6285 SECURITY_INFORMATION si =
6286 OWNER_SECURITY_INFORMATION |
6287 GROUP_SECURITY_INFORMATION |
6288 DACL_SECURITY_INFORMATION ;
6289 int e = errno;
6291 filename = map_w32_filename (fname, NULL);
6292 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
6293 fname = chase_symlinks (filename);
6294 else
6295 fname = filename;
6297 errno = 0;
6298 if (!get_file_security (fname, si, psd, 0, &sd_len)
6299 && errno != ENOTSUP)
6301 err = GetLastError ();
6302 if (err == ERROR_INSUFFICIENT_BUFFER)
6304 psd = xmalloc (sd_len);
6305 if (!get_file_security (fname, si, psd, sd_len, &sd_len))
6307 xfree (psd);
6308 errno = EIO;
6309 psd = NULL;
6312 else if (err == ERROR_FILE_NOT_FOUND
6313 || err == ERROR_PATH_NOT_FOUND
6314 /* ERROR_INVALID_NAME is what we get if
6315 w32-unicode-filenames is nil and the file cannot
6316 be encoded in the current ANSI codepage. */
6317 || err == ERROR_INVALID_NAME)
6318 errno = ENOENT;
6319 else
6320 errno = EIO;
6322 else if (!errno)
6323 errno = e;
6325 else if (type != ACL_TYPE_DEFAULT)
6326 errno = EINVAL;
6328 return psd;
6332 acl_set_file (const char *fname, acl_type_t type, acl_t acl)
6334 TOKEN_PRIVILEGES old1, old2;
6335 DWORD err;
6336 int st = 0, retval = -1;
6337 SECURITY_INFORMATION flags = 0;
6338 PSID psidOwner, psidGroup;
6339 PACL pacl;
6340 BOOL dflt;
6341 BOOL dacl_present;
6342 int e;
6343 const char *filename;
6345 if (acl_valid (acl) != 0
6346 || (type != ACL_TYPE_DEFAULT && type != ACL_TYPE_ACCESS))
6348 errno = EINVAL;
6349 return -1;
6352 if (type == ACL_TYPE_DEFAULT)
6354 errno = ENOSYS;
6355 return -1;
6358 filename = map_w32_filename (fname, NULL);
6359 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
6360 fname = chase_symlinks (filename);
6361 else
6362 fname = filename;
6364 if (get_security_descriptor_owner ((PSECURITY_DESCRIPTOR)acl, &psidOwner,
6365 &dflt)
6366 && psidOwner)
6367 flags |= OWNER_SECURITY_INFORMATION;
6368 if (get_security_descriptor_group ((PSECURITY_DESCRIPTOR)acl, &psidGroup,
6369 &dflt)
6370 && psidGroup)
6371 flags |= GROUP_SECURITY_INFORMATION;
6372 if (get_security_descriptor_dacl ((PSECURITY_DESCRIPTOR)acl, &dacl_present,
6373 &pacl, &dflt)
6374 && dacl_present)
6375 flags |= DACL_SECURITY_INFORMATION;
6376 if (!flags)
6377 return 0;
6379 /* According to KB-245153, setting the owner will succeed if either:
6380 (1) the caller is the user who will be the new owner, and has the
6381 SE_TAKE_OWNERSHIP privilege, or
6382 (2) the caller has the SE_RESTORE privilege, in which case she can
6383 set any valid user or group as the owner
6385 We request below both SE_TAKE_OWNERSHIP and SE_RESTORE
6386 privileges, and disregard any failures in obtaining them. If
6387 these privileges cannot be obtained, and do not already exist in
6388 the calling thread's security token, this function could fail
6389 with EPERM. */
6390 if (enable_privilege (SE_TAKE_OWNERSHIP_NAME, TRUE, &old1))
6391 st++;
6392 if (enable_privilege (SE_RESTORE_NAME, TRUE, &old2))
6393 st++;
6395 e = errno;
6396 errno = 0;
6397 /* SetFileSecurity is deprecated by MS, and sometimes fails when
6398 DACL inheritance is involved, but it seems to preserve ownership
6399 better than SetNamedSecurityInfo, which is important e.g., in
6400 copy-file. */
6401 if (!set_file_security (fname, flags, (PSECURITY_DESCRIPTOR)acl))
6403 err = GetLastError ();
6405 if (errno != ENOTSUP)
6406 err = set_named_security_info (fname, SE_FILE_OBJECT, flags,
6407 psidOwner, psidGroup, pacl, NULL);
6409 else
6410 err = ERROR_SUCCESS;
6411 if (err != ERROR_SUCCESS)
6413 if (errno == ENOTSUP)
6415 else if (err == ERROR_INVALID_OWNER
6416 || err == ERROR_NOT_ALL_ASSIGNED
6417 || err == ERROR_ACCESS_DENIED)
6419 /* Maybe the requested ACL and the one the file already has
6420 are identical, in which case we can silently ignore the
6421 failure. (And no, Windows doesn't.) */
6422 acl_t current_acl = acl_get_file (fname, ACL_TYPE_ACCESS);
6424 errno = EPERM;
6425 if (current_acl)
6427 char *acl_from = acl_to_text (current_acl, NULL);
6428 char *acl_to = acl_to_text (acl, NULL);
6430 if (acl_from && acl_to && xstrcasecmp (acl_from, acl_to) == 0)
6432 retval = 0;
6433 errno = e;
6435 if (acl_from)
6436 acl_free (acl_from);
6437 if (acl_to)
6438 acl_free (acl_to);
6439 acl_free (current_acl);
6442 else if (err == ERROR_FILE_NOT_FOUND
6443 || err == ERROR_PATH_NOT_FOUND
6444 /* ERROR_INVALID_NAME is what we get if
6445 w32-unicode-filenames is nil and the file cannot be
6446 encoded in the current ANSI codepage. */
6447 || err == ERROR_INVALID_NAME)
6448 errno = ENOENT;
6449 else
6450 errno = EACCES;
6452 else
6454 retval = 0;
6455 errno = e;
6458 if (st)
6460 if (st >= 2)
6461 restore_privilege (&old2);
6462 restore_privilege (&old1);
6463 revert_to_self ();
6466 return retval;
6469 /* Return true if errno value ERRNUM indicates that ACLs are well
6470 supported on this system. ERRNUM should be an errno value obtained
6471 after an ACL-related system call fails. */
6472 bool
6473 acl_errno_valid (int errnum)
6475 switch (errnum)
6477 case EBUSY:
6478 case EINVAL:
6479 case ENOTSUP:
6480 return false;
6481 default:
6482 return true;
6487 /* MS-Windows version of careadlinkat (cf. ../lib/careadlinkat.c). We
6488 have a fixed max size for file names, so we don't need the kind of
6489 alloc/malloc/realloc dance the gnulib version does. We also don't
6490 support FD-relative symlinks. */
6491 char *
6492 careadlinkat (int fd, char const *filename,
6493 char *buffer, size_t buffer_size,
6494 struct allocator const *alloc,
6495 ssize_t (*preadlinkat) (int, char const *, char *, size_t))
6497 char linkname[MAX_UTF8_PATH];
6498 ssize_t link_size;
6500 link_size = preadlinkat (fd, filename, linkname, sizeof(linkname));
6502 if (link_size > 0)
6504 char *retval = buffer;
6506 linkname[link_size++] = '\0';
6507 if (link_size > buffer_size)
6508 retval = (char *)(alloc ? alloc->allocate : xmalloc) (link_size);
6509 if (retval)
6510 memcpy (retval, linkname, link_size);
6512 return retval;
6514 return NULL;
6518 w32_copy_file (const char *from, const char *to,
6519 int keep_time, int preserve_ownership, int copy_acls)
6521 acl_t acl = NULL;
6522 BOOL copy_result;
6523 wchar_t from_w[MAX_PATH], to_w[MAX_PATH];
6524 char from_a[MAX_PATH], to_a[MAX_PATH];
6526 /* We ignore preserve_ownership for now. */
6527 preserve_ownership = preserve_ownership;
6529 if (copy_acls)
6531 acl = acl_get_file (from, ACL_TYPE_ACCESS);
6532 if (acl == NULL && acl_errno_valid (errno))
6533 return -2;
6535 if (w32_unicode_filenames)
6537 filename_to_utf16 (from, from_w);
6538 filename_to_utf16 (to, to_w);
6539 copy_result = CopyFileW (from_w, to_w, FALSE);
6541 else
6543 filename_to_ansi (from, from_a);
6544 filename_to_ansi (to, to_a);
6545 copy_result = CopyFileA (from_a, to_a, FALSE);
6547 if (!copy_result)
6549 /* CopyFile doesn't set errno when it fails. By far the most
6550 "popular" reason is that the target is read-only. */
6551 DWORD err = GetLastError ();
6553 switch (err)
6555 case ERROR_FILE_NOT_FOUND:
6556 errno = ENOENT;
6557 break;
6558 case ERROR_ACCESS_DENIED:
6559 errno = EACCES;
6560 break;
6561 case ERROR_ENCRYPTION_FAILED:
6562 errno = EIO;
6563 break;
6564 default:
6565 errno = EPERM;
6566 break;
6569 if (acl)
6570 acl_free (acl);
6571 return -1;
6573 /* CopyFile retains the timestamp by default. However, see
6574 "Community Additions" for CopyFile: it sounds like that is not
6575 entirely true. Testing on Windows XP confirms that modified time
6576 is copied, but creation and last-access times are not.
6577 FIXME? */
6578 else if (!keep_time)
6580 struct timespec now;
6581 DWORD attributes;
6583 if (w32_unicode_filenames)
6585 /* Ensure file is writable while its times are set. */
6586 attributes = GetFileAttributesW (to_w);
6587 SetFileAttributesW (to_w, attributes & ~FILE_ATTRIBUTE_READONLY);
6588 now = current_timespec ();
6589 if (set_file_times (-1, to, now, now))
6591 /* Restore original attributes. */
6592 SetFileAttributesW (to_w, attributes);
6593 if (acl)
6594 acl_free (acl);
6595 return -3;
6597 /* Restore original attributes. */
6598 SetFileAttributesW (to_w, attributes);
6600 else
6602 attributes = GetFileAttributesA (to_a);
6603 SetFileAttributesA (to_a, attributes & ~FILE_ATTRIBUTE_READONLY);
6604 now = current_timespec ();
6605 if (set_file_times (-1, to, now, now))
6607 SetFileAttributesA (to_a, attributes);
6608 if (acl)
6609 acl_free (acl);
6610 return -3;
6612 SetFileAttributesA (to_a, attributes);
6615 if (acl != NULL)
6617 bool fail =
6618 acl_set_file (to, ACL_TYPE_ACCESS, acl) != 0;
6619 acl_free (acl);
6620 if (fail && acl_errno_valid (errno))
6621 return -4;
6624 return 0;
6628 /* Support for browsing other processes and their attributes. See
6629 process.c for the Lisp bindings. */
6631 /* Helper wrapper functions. */
6633 static HANDLE WINAPI
6634 create_toolhelp32_snapshot (DWORD Flags, DWORD Ignored)
6636 static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot = NULL;
6638 if (g_b_init_create_toolhelp32_snapshot == 0)
6640 g_b_init_create_toolhelp32_snapshot = 1;
6641 s_pfn_Create_Toolhelp32_Snapshot = (CreateToolhelp32Snapshot_Proc)
6642 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6643 "CreateToolhelp32Snapshot");
6645 if (s_pfn_Create_Toolhelp32_Snapshot == NULL)
6647 return INVALID_HANDLE_VALUE;
6649 return (s_pfn_Create_Toolhelp32_Snapshot (Flags, Ignored));
6652 static BOOL WINAPI
6653 process32_first (HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
6655 static Process32First_Proc s_pfn_Process32_First = NULL;
6657 if (g_b_init_process32_first == 0)
6659 g_b_init_process32_first = 1;
6660 s_pfn_Process32_First = (Process32First_Proc)
6661 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6662 "Process32First");
6664 if (s_pfn_Process32_First == NULL)
6666 return FALSE;
6668 return (s_pfn_Process32_First (hSnapshot, lppe));
6671 static BOOL WINAPI
6672 process32_next (HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
6674 static Process32Next_Proc s_pfn_Process32_Next = NULL;
6676 if (g_b_init_process32_next == 0)
6678 g_b_init_process32_next = 1;
6679 s_pfn_Process32_Next = (Process32Next_Proc)
6680 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6681 "Process32Next");
6683 if (s_pfn_Process32_Next == NULL)
6685 return FALSE;
6687 return (s_pfn_Process32_Next (hSnapshot, lppe));
6690 static BOOL WINAPI
6691 open_thread_token (HANDLE ThreadHandle,
6692 DWORD DesiredAccess,
6693 BOOL OpenAsSelf,
6694 PHANDLE TokenHandle)
6696 static OpenThreadToken_Proc s_pfn_Open_Thread_Token = NULL;
6697 HMODULE hm_advapi32 = NULL;
6698 if (is_windows_9x () == TRUE)
6700 SetLastError (ERROR_NOT_SUPPORTED);
6701 return FALSE;
6703 if (g_b_init_open_thread_token == 0)
6705 g_b_init_open_thread_token = 1;
6706 hm_advapi32 = LoadLibrary ("Advapi32.dll");
6707 s_pfn_Open_Thread_Token =
6708 (OpenThreadToken_Proc) GetProcAddress (hm_advapi32, "OpenThreadToken");
6710 if (s_pfn_Open_Thread_Token == NULL)
6712 SetLastError (ERROR_NOT_SUPPORTED);
6713 return FALSE;
6715 return (
6716 s_pfn_Open_Thread_Token (
6717 ThreadHandle,
6718 DesiredAccess,
6719 OpenAsSelf,
6720 TokenHandle)
6724 static BOOL WINAPI
6725 impersonate_self (SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
6727 static ImpersonateSelf_Proc s_pfn_Impersonate_Self = NULL;
6728 HMODULE hm_advapi32 = NULL;
6729 if (is_windows_9x () == TRUE)
6731 return FALSE;
6733 if (g_b_init_impersonate_self == 0)
6735 g_b_init_impersonate_self = 1;
6736 hm_advapi32 = LoadLibrary ("Advapi32.dll");
6737 s_pfn_Impersonate_Self =
6738 (ImpersonateSelf_Proc) GetProcAddress (hm_advapi32, "ImpersonateSelf");
6740 if (s_pfn_Impersonate_Self == NULL)
6742 return FALSE;
6744 return s_pfn_Impersonate_Self (ImpersonationLevel);
6747 static BOOL WINAPI
6748 revert_to_self (void)
6750 static RevertToSelf_Proc s_pfn_Revert_To_Self = NULL;
6751 HMODULE hm_advapi32 = NULL;
6752 if (is_windows_9x () == TRUE)
6754 return FALSE;
6756 if (g_b_init_revert_to_self == 0)
6758 g_b_init_revert_to_self = 1;
6759 hm_advapi32 = LoadLibrary ("Advapi32.dll");
6760 s_pfn_Revert_To_Self =
6761 (RevertToSelf_Proc) GetProcAddress (hm_advapi32, "RevertToSelf");
6763 if (s_pfn_Revert_To_Self == NULL)
6765 return FALSE;
6767 return s_pfn_Revert_To_Self ();
6770 static BOOL WINAPI
6771 get_process_memory_info (HANDLE h_proc,
6772 PPROCESS_MEMORY_COUNTERS mem_counters,
6773 DWORD bufsize)
6775 static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info = NULL;
6776 HMODULE hm_psapi = NULL;
6777 if (is_windows_9x () == TRUE)
6779 return FALSE;
6781 if (g_b_init_get_process_memory_info == 0)
6783 g_b_init_get_process_memory_info = 1;
6784 hm_psapi = LoadLibrary ("Psapi.dll");
6785 if (hm_psapi)
6786 s_pfn_Get_Process_Memory_Info = (GetProcessMemoryInfo_Proc)
6787 GetProcAddress (hm_psapi, "GetProcessMemoryInfo");
6789 if (s_pfn_Get_Process_Memory_Info == NULL)
6791 return FALSE;
6793 return s_pfn_Get_Process_Memory_Info (h_proc, mem_counters, bufsize);
6796 static BOOL WINAPI
6797 get_process_working_set_size (HANDLE h_proc,
6798 PSIZE_T minrss,
6799 PSIZE_T maxrss)
6801 static GetProcessWorkingSetSize_Proc
6802 s_pfn_Get_Process_Working_Set_Size = NULL;
6804 if (is_windows_9x () == TRUE)
6806 return FALSE;
6808 if (g_b_init_get_process_working_set_size == 0)
6810 g_b_init_get_process_working_set_size = 1;
6811 s_pfn_Get_Process_Working_Set_Size = (GetProcessWorkingSetSize_Proc)
6812 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6813 "GetProcessWorkingSetSize");
6815 if (s_pfn_Get_Process_Working_Set_Size == NULL)
6817 return FALSE;
6819 return s_pfn_Get_Process_Working_Set_Size (h_proc, minrss, maxrss);
6822 static BOOL WINAPI
6823 global_memory_status (MEMORYSTATUS *buf)
6825 static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status = NULL;
6827 if (is_windows_9x () == TRUE)
6829 return FALSE;
6831 if (g_b_init_global_memory_status == 0)
6833 g_b_init_global_memory_status = 1;
6834 s_pfn_Global_Memory_Status = (GlobalMemoryStatus_Proc)
6835 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6836 "GlobalMemoryStatus");
6838 if (s_pfn_Global_Memory_Status == NULL)
6840 return FALSE;
6842 return s_pfn_Global_Memory_Status (buf);
6845 static BOOL WINAPI
6846 global_memory_status_ex (MEMORY_STATUS_EX *buf)
6848 static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex = NULL;
6850 if (is_windows_9x () == TRUE)
6852 return FALSE;
6854 if (g_b_init_global_memory_status_ex == 0)
6856 g_b_init_global_memory_status_ex = 1;
6857 s_pfn_Global_Memory_Status_Ex = (GlobalMemoryStatusEx_Proc)
6858 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6859 "GlobalMemoryStatusEx");
6861 if (s_pfn_Global_Memory_Status_Ex == NULL)
6863 return FALSE;
6865 return s_pfn_Global_Memory_Status_Ex (buf);
6868 Lisp_Object
6869 list_system_processes (void)
6871 Lisp_Object proclist = Qnil;
6872 HANDLE h_snapshot;
6874 h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
6876 if (h_snapshot != INVALID_HANDLE_VALUE)
6878 PROCESSENTRY32 proc_entry;
6879 DWORD proc_id;
6880 BOOL res;
6882 proc_entry.dwSize = sizeof (PROCESSENTRY32);
6883 for (res = process32_first (h_snapshot, &proc_entry); res;
6884 res = process32_next (h_snapshot, &proc_entry))
6886 proc_id = proc_entry.th32ProcessID;
6887 proclist = Fcons (make_fixnum_or_float (proc_id), proclist);
6890 CloseHandle (h_snapshot);
6891 proclist = Fnreverse (proclist);
6894 return proclist;
6897 static int
6898 enable_privilege (LPCTSTR priv_name, BOOL enable_p, TOKEN_PRIVILEGES *old_priv)
6900 TOKEN_PRIVILEGES priv;
6901 DWORD priv_size = sizeof (priv);
6902 DWORD opriv_size = sizeof (*old_priv);
6903 HANDLE h_token = NULL;
6904 HANDLE h_thread = GetCurrentThread ();
6905 int ret_val = 0;
6906 BOOL res;
6908 res = open_thread_token (h_thread,
6909 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
6910 FALSE, &h_token);
6911 if (!res && GetLastError () == ERROR_NO_TOKEN)
6913 if (impersonate_self (SecurityImpersonation))
6914 res = open_thread_token (h_thread,
6915 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
6916 FALSE, &h_token);
6918 if (res)
6920 priv.PrivilegeCount = 1;
6921 priv.Privileges[0].Attributes = enable_p ? SE_PRIVILEGE_ENABLED : 0;
6922 LookupPrivilegeValue (NULL, priv_name, &priv.Privileges[0].Luid);
6923 if (AdjustTokenPrivileges (h_token, FALSE, &priv, priv_size,
6924 old_priv, &opriv_size)
6925 && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
6926 ret_val = 1;
6928 if (h_token)
6929 CloseHandle (h_token);
6931 return ret_val;
6934 static int
6935 restore_privilege (TOKEN_PRIVILEGES *priv)
6937 DWORD priv_size = sizeof (*priv);
6938 HANDLE h_token = NULL;
6939 int ret_val = 0;
6941 if (open_thread_token (GetCurrentThread (),
6942 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
6943 FALSE, &h_token))
6945 if (AdjustTokenPrivileges (h_token, FALSE, priv, priv_size, NULL, NULL)
6946 && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
6947 ret_val = 1;
6949 if (h_token)
6950 CloseHandle (h_token);
6952 return ret_val;
6955 static Lisp_Object
6956 ltime (ULONGLONG time_100ns)
6958 ULONGLONG time_sec = time_100ns / 10000000;
6959 int subsec = time_100ns % 10000000;
6960 return list4i (time_sec >> 16, time_sec & 0xffff,
6961 subsec / 10, subsec % 10 * 100000);
6964 #define U64_TO_LISP_TIME(time) ltime (time)
6966 static int
6967 process_times (HANDLE h_proc, Lisp_Object *ctime, Lisp_Object *etime,
6968 Lisp_Object *stime, Lisp_Object *utime, Lisp_Object *ttime,
6969 double *pcpu)
6971 FILETIME ft_creation, ft_exit, ft_kernel, ft_user, ft_current;
6972 ULONGLONG tem1, tem2, tem3, tem;
6974 if (!h_proc
6975 || !get_process_times_fn
6976 || !(*get_process_times_fn) (h_proc, &ft_creation, &ft_exit,
6977 &ft_kernel, &ft_user))
6978 return 0;
6980 GetSystemTimeAsFileTime (&ft_current);
6982 FILETIME_TO_U64 (tem1, ft_kernel);
6983 *stime = U64_TO_LISP_TIME (tem1);
6985 FILETIME_TO_U64 (tem2, ft_user);
6986 *utime = U64_TO_LISP_TIME (tem2);
6988 tem3 = tem1 + tem2;
6989 *ttime = U64_TO_LISP_TIME (tem3);
6991 FILETIME_TO_U64 (tem, ft_creation);
6992 /* Process no 4 (System) returns zero creation time. */
6993 if (tem)
6994 tem -= utc_base;
6995 *ctime = U64_TO_LISP_TIME (tem);
6997 if (tem)
6999 FILETIME_TO_U64 (tem3, ft_current);
7000 tem = (tem3 - utc_base) - tem;
7002 *etime = U64_TO_LISP_TIME (tem);
7004 if (tem)
7006 *pcpu = 100.0 * (tem1 + tem2) / tem;
7007 if (*pcpu > 100)
7008 *pcpu = 100.0;
7010 else
7011 *pcpu = 0;
7013 return 1;
7016 Lisp_Object
7017 system_process_attributes (Lisp_Object pid)
7019 Lisp_Object attrs = Qnil;
7020 Lisp_Object cmd_str, decoded_cmd, tem;
7021 HANDLE h_snapshot, h_proc;
7022 DWORD proc_id;
7023 int found_proc = 0;
7024 char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
7025 DWORD ulength = sizeof (uname), dlength = sizeof (domain), needed;
7026 DWORD glength = sizeof (gname);
7027 HANDLE token = NULL;
7028 SID_NAME_USE user_type;
7029 unsigned char *buf = NULL;
7030 DWORD blen = 0;
7031 TOKEN_USER user_token;
7032 TOKEN_PRIMARY_GROUP group_token;
7033 unsigned euid;
7034 unsigned egid;
7035 PROCESS_MEMORY_COUNTERS mem;
7036 PROCESS_MEMORY_COUNTERS_EX mem_ex;
7037 SIZE_T minrss, maxrss;
7038 MEMORYSTATUS memst;
7039 MEMORY_STATUS_EX memstex;
7040 double totphys = 0.0;
7041 Lisp_Object ctime, stime, utime, etime, ttime;
7042 double pcpu;
7043 BOOL result = FALSE;
7045 CHECK_NUMBER_OR_FLOAT (pid);
7046 proc_id = FLOATP (pid) ? XFLOAT_DATA (pid) : XINT (pid);
7048 h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
7050 if (h_snapshot != INVALID_HANDLE_VALUE)
7052 PROCESSENTRY32 pe;
7053 BOOL res;
7055 pe.dwSize = sizeof (PROCESSENTRY32);
7056 for (res = process32_first (h_snapshot, &pe); res;
7057 res = process32_next (h_snapshot, &pe))
7059 if (proc_id == pe.th32ProcessID)
7061 if (proc_id == 0)
7062 decoded_cmd = build_string ("Idle");
7063 else
7065 /* Decode the command name from locale-specific
7066 encoding. */
7067 cmd_str = build_unibyte_string (pe.szExeFile);
7069 decoded_cmd =
7070 code_convert_string_norecord (cmd_str,
7071 Vlocale_coding_system, 0);
7073 attrs = Fcons (Fcons (Qcomm, decoded_cmd), attrs);
7074 attrs = Fcons (Fcons (Qppid,
7075 make_fixnum_or_float (pe.th32ParentProcessID)),
7076 attrs);
7077 attrs = Fcons (Fcons (Qpri, make_number (pe.pcPriClassBase)),
7078 attrs);
7079 attrs = Fcons (Fcons (Qthcount,
7080 make_fixnum_or_float (pe.cntThreads)),
7081 attrs);
7082 found_proc = 1;
7083 break;
7087 CloseHandle (h_snapshot);
7090 if (!found_proc)
7091 return Qnil;
7093 h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
7094 FALSE, proc_id);
7095 /* If we were denied a handle to the process, try again after
7096 enabling the SeDebugPrivilege in our process. */
7097 if (!h_proc)
7099 TOKEN_PRIVILEGES priv_current;
7101 if (enable_privilege (SE_DEBUG_NAME, TRUE, &priv_current))
7103 h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
7104 FALSE, proc_id);
7105 restore_privilege (&priv_current);
7106 revert_to_self ();
7109 if (h_proc)
7111 result = open_process_token (h_proc, TOKEN_QUERY, &token);
7112 if (result)
7114 result = get_token_information (token, TokenUser, NULL, 0, &blen);
7115 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
7117 buf = xmalloc (blen);
7118 result = get_token_information (token, TokenUser,
7119 (LPVOID)buf, blen, &needed);
7120 if (result)
7122 memcpy (&user_token, buf, sizeof (user_token));
7123 if (!w32_cached_id (user_token.User.Sid, &euid, uname))
7125 euid = get_rid (user_token.User.Sid);
7126 result = lookup_account_sid (NULL, user_token.User.Sid,
7127 uname, &ulength,
7128 domain, &dlength,
7129 &user_type);
7130 if (result)
7131 w32_add_to_cache (user_token.User.Sid, euid, uname);
7132 else
7134 strcpy (uname, "unknown");
7135 result = TRUE;
7138 ulength = strlen (uname);
7142 if (result)
7144 /* Determine a reasonable euid and gid values. */
7145 if (xstrcasecmp ("administrator", uname) == 0)
7147 euid = 500; /* well-known Administrator uid */
7148 egid = 513; /* well-known None gid */
7150 else
7152 /* Get group id and name. */
7153 result = get_token_information (token, TokenPrimaryGroup,
7154 (LPVOID)buf, blen, &needed);
7155 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
7157 buf = xrealloc (buf, blen = needed);
7158 result = get_token_information (token, TokenPrimaryGroup,
7159 (LPVOID)buf, blen, &needed);
7161 if (result)
7163 memcpy (&group_token, buf, sizeof (group_token));
7164 if (!w32_cached_id (group_token.PrimaryGroup, &egid, gname))
7166 egid = get_rid (group_token.PrimaryGroup);
7167 dlength = sizeof (domain);
7168 result =
7169 lookup_account_sid (NULL, group_token.PrimaryGroup,
7170 gname, &glength, NULL, &dlength,
7171 &user_type);
7172 if (result)
7173 w32_add_to_cache (group_token.PrimaryGroup,
7174 egid, gname);
7175 else
7177 strcpy (gname, "None");
7178 result = TRUE;
7181 glength = strlen (gname);
7185 xfree (buf);
7187 if (!result)
7189 if (!is_windows_9x ())
7191 /* We couldn't open the process token, presumably because of
7192 insufficient access rights. Assume this process is run
7193 by the system. */
7194 strcpy (uname, "SYSTEM");
7195 strcpy (gname, "None");
7196 euid = 18; /* SYSTEM */
7197 egid = 513; /* None */
7198 glength = strlen (gname);
7199 ulength = strlen (uname);
7201 /* If we are running under Windows 9X, where security calls are
7202 not supported, we assume all processes are run by the current
7203 user. */
7204 else if (GetUserName (uname, &ulength))
7206 if (xstrcasecmp ("administrator", uname) == 0)
7207 euid = 0;
7208 else
7209 euid = 123;
7210 egid = euid;
7211 strcpy (gname, "None");
7212 glength = strlen (gname);
7213 ulength = strlen (uname);
7215 else
7217 euid = 123;
7218 egid = 123;
7219 strcpy (uname, "administrator");
7220 ulength = strlen (uname);
7221 strcpy (gname, "None");
7222 glength = strlen (gname);
7224 if (token)
7225 CloseHandle (token);
7228 attrs = Fcons (Fcons (Qeuid, make_fixnum_or_float (euid)), attrs);
7229 tem = make_unibyte_string (uname, ulength);
7230 attrs = Fcons (Fcons (Quser,
7231 code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
7232 attrs);
7233 attrs = Fcons (Fcons (Qegid, make_fixnum_or_float (egid)), attrs);
7234 tem = make_unibyte_string (gname, glength);
7235 attrs = Fcons (Fcons (Qgroup,
7236 code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
7237 attrs);
7239 if (global_memory_status_ex (&memstex))
7240 #if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
7241 totphys = memstex.ullTotalPhys / 1024.0;
7242 #else
7243 /* Visual Studio 6 cannot convert an unsigned __int64 type to
7244 double, so we need to do this for it... */
7246 DWORD tot_hi = memstex.ullTotalPhys >> 32;
7247 DWORD tot_md = (memstex.ullTotalPhys & 0x00000000ffffffff) >> 10;
7248 DWORD tot_lo = memstex.ullTotalPhys % 1024;
7250 totphys = tot_hi * 4194304.0 + tot_md + tot_lo / 1024.0;
7252 #endif /* __GNUC__ || _MSC_VER >= 1300 */
7253 else if (global_memory_status (&memst))
7254 totphys = memst.dwTotalPhys / 1024.0;
7256 if (h_proc
7257 && get_process_memory_info (h_proc, (PROCESS_MEMORY_COUNTERS *)&mem_ex,
7258 sizeof (mem_ex)))
7260 SIZE_T rss = mem_ex.WorkingSetSize / 1024;
7262 attrs = Fcons (Fcons (Qmajflt,
7263 make_fixnum_or_float (mem_ex.PageFaultCount)),
7264 attrs);
7265 attrs = Fcons (Fcons (Qvsize,
7266 make_fixnum_or_float (mem_ex.PrivateUsage / 1024)),
7267 attrs);
7268 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (rss)), attrs);
7269 if (totphys)
7270 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
7272 else if (h_proc
7273 && get_process_memory_info (h_proc, &mem, sizeof (mem)))
7275 SIZE_T rss = mem_ex.WorkingSetSize / 1024;
7277 attrs = Fcons (Fcons (Qmajflt,
7278 make_fixnum_or_float (mem.PageFaultCount)),
7279 attrs);
7280 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (rss)), attrs);
7281 if (totphys)
7282 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
7284 else if (h_proc
7285 && get_process_working_set_size (h_proc, &minrss, &maxrss))
7287 DWORD rss = maxrss / 1024;
7289 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (maxrss / 1024)), attrs);
7290 if (totphys)
7291 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
7294 if (process_times (h_proc, &ctime, &etime, &stime, &utime, &ttime, &pcpu))
7296 attrs = Fcons (Fcons (Qutime, utime), attrs);
7297 attrs = Fcons (Fcons (Qstime, stime), attrs);
7298 attrs = Fcons (Fcons (Qtime, ttime), attrs);
7299 attrs = Fcons (Fcons (Qstart, ctime), attrs);
7300 attrs = Fcons (Fcons (Qetime, etime), attrs);
7301 attrs = Fcons (Fcons (Qpcpu, make_float (pcpu)), attrs);
7304 /* FIXME: Retrieve command line by walking the PEB of the process. */
7306 if (h_proc)
7307 CloseHandle (h_proc);
7308 return attrs;
7312 w32_memory_info (unsigned long long *totalram, unsigned long long *freeram,
7313 unsigned long long *totalswap, unsigned long long *freeswap)
7315 MEMORYSTATUS memst;
7316 MEMORY_STATUS_EX memstex;
7318 /* Use GlobalMemoryStatusEx if available, as it can report more than
7319 2GB of memory. */
7320 if (global_memory_status_ex (&memstex))
7322 *totalram = memstex.ullTotalPhys;
7323 *freeram = memstex.ullAvailPhys;
7324 *totalswap = memstex.ullTotalPageFile;
7325 *freeswap = memstex.ullAvailPageFile;
7326 return 0;
7328 else if (global_memory_status (&memst))
7330 *totalram = memst.dwTotalPhys;
7331 *freeram = memst.dwAvailPhys;
7332 *totalswap = memst.dwTotalPageFile;
7333 *freeswap = memst.dwAvailPageFile;
7334 return 0;
7336 else
7337 return -1;
7341 /* Wrappers for winsock functions to map between our file descriptors
7342 and winsock's handles; also set h_errno for convenience.
7344 To allow Emacs to run on systems which don't have winsock support
7345 installed, we dynamically link to winsock on startup if present, and
7346 otherwise provide the minimum necessary functionality
7347 (eg. gethostname). */
7349 /* function pointers for relevant socket functions */
7350 int (PASCAL *pfn_WSAStartup) (WORD wVersionRequired, LPWSADATA lpWSAData);
7351 void (PASCAL *pfn_WSASetLastError) (int iError);
7352 int (PASCAL *pfn_WSAGetLastError) (void);
7353 int (PASCAL *pfn_WSAEventSelect) (SOCKET s, HANDLE hEventObject, long lNetworkEvents);
7354 int (PASCAL *pfn_WSAEnumNetworkEvents) (SOCKET s, HANDLE hEventObject,
7355 WSANETWORKEVENTS *NetworkEvents);
7357 HANDLE (PASCAL *pfn_WSACreateEvent) (void);
7358 int (PASCAL *pfn_WSACloseEvent) (HANDLE hEvent);
7359 int (PASCAL *pfn_socket) (int af, int type, int protocol);
7360 int (PASCAL *pfn_bind) (SOCKET s, const struct sockaddr *addr, int namelen);
7361 int (PASCAL *pfn_connect) (SOCKET s, const struct sockaddr *addr, int namelen);
7362 int (PASCAL *pfn_ioctlsocket) (SOCKET s, long cmd, u_long *argp);
7363 int (PASCAL *pfn_recv) (SOCKET s, char * buf, int len, int flags);
7364 int (PASCAL *pfn_send) (SOCKET s, const char * buf, int len, int flags);
7365 int (PASCAL *pfn_closesocket) (SOCKET s);
7366 int (PASCAL *pfn_shutdown) (SOCKET s, int how);
7367 int (PASCAL *pfn_WSACleanup) (void);
7369 u_short (PASCAL *pfn_htons) (u_short hostshort);
7370 u_short (PASCAL *pfn_ntohs) (u_short netshort);
7371 unsigned long (PASCAL *pfn_inet_addr) (const char * cp);
7372 int (PASCAL *pfn_gethostname) (char * name, int namelen);
7373 struct hostent * (PASCAL *pfn_gethostbyname) (const char * name);
7374 struct servent * (PASCAL *pfn_getservbyname) (const char * name, const char * proto);
7375 int (PASCAL *pfn_getpeername) (SOCKET s, struct sockaddr *addr, int * namelen);
7376 int (PASCAL *pfn_setsockopt) (SOCKET s, int level, int optname,
7377 const char * optval, int optlen);
7378 int (PASCAL *pfn_listen) (SOCKET s, int backlog);
7379 int (PASCAL *pfn_getsockname) (SOCKET s, struct sockaddr * name,
7380 int * namelen);
7381 SOCKET (PASCAL *pfn_accept) (SOCKET s, struct sockaddr * addr, int * addrlen);
7382 int (PASCAL *pfn_recvfrom) (SOCKET s, char * buf, int len, int flags,
7383 struct sockaddr * from, int * fromlen);
7384 int (PASCAL *pfn_sendto) (SOCKET s, const char * buf, int len, int flags,
7385 const struct sockaddr * to, int tolen);
7387 int (PASCAL *pfn_getaddrinfo) (const char *, const char *,
7388 const struct addrinfo *, struct addrinfo **);
7389 void (PASCAL *pfn_freeaddrinfo) (struct addrinfo *);
7391 /* SetHandleInformation is only needed to make sockets non-inheritable. */
7392 BOOL (WINAPI *pfn_SetHandleInformation) (HANDLE object, DWORD mask, DWORD flags);
7393 #ifndef HANDLE_FLAG_INHERIT
7394 #define HANDLE_FLAG_INHERIT 1
7395 #endif
7397 HANDLE winsock_lib;
7398 static int winsock_inuse;
7400 BOOL term_winsock (void);
7402 BOOL
7403 term_winsock (void)
7405 if (winsock_lib != NULL && winsock_inuse == 0)
7407 release_listen_threads ();
7408 /* Not sure what would cause WSAENETDOWN, or even if it can happen
7409 after WSAStartup returns successfully, but it seems reasonable
7410 to allow unloading winsock anyway in that case. */
7411 if (pfn_WSACleanup () == 0 ||
7412 pfn_WSAGetLastError () == WSAENETDOWN)
7414 if (FreeLibrary (winsock_lib))
7415 winsock_lib = NULL;
7416 return TRUE;
7419 return FALSE;
7422 BOOL
7423 init_winsock (int load_now)
7425 WSADATA winsockData;
7427 if (winsock_lib != NULL)
7428 return TRUE;
7430 pfn_SetHandleInformation
7431 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
7432 "SetHandleInformation");
7434 winsock_lib = LoadLibrary ("Ws2_32.dll");
7436 if (winsock_lib != NULL)
7438 /* dynamically link to socket functions */
7440 #define LOAD_PROC(fn) \
7441 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
7442 goto fail;
7444 LOAD_PROC (WSAStartup);
7445 LOAD_PROC (WSASetLastError);
7446 LOAD_PROC (WSAGetLastError);
7447 LOAD_PROC (WSAEventSelect);
7448 LOAD_PROC (WSAEnumNetworkEvents);
7449 LOAD_PROC (WSACreateEvent);
7450 LOAD_PROC (WSACloseEvent);
7451 LOAD_PROC (socket);
7452 LOAD_PROC (bind);
7453 LOAD_PROC (connect);
7454 LOAD_PROC (ioctlsocket);
7455 LOAD_PROC (recv);
7456 LOAD_PROC (send);
7457 LOAD_PROC (closesocket);
7458 LOAD_PROC (shutdown);
7459 LOAD_PROC (htons);
7460 LOAD_PROC (ntohs);
7461 LOAD_PROC (inet_addr);
7462 LOAD_PROC (gethostname);
7463 LOAD_PROC (gethostbyname);
7464 LOAD_PROC (getservbyname);
7465 LOAD_PROC (getpeername);
7466 LOAD_PROC (WSACleanup);
7467 LOAD_PROC (setsockopt);
7468 LOAD_PROC (listen);
7469 LOAD_PROC (getsockname);
7470 LOAD_PROC (accept);
7471 LOAD_PROC (recvfrom);
7472 LOAD_PROC (sendto);
7473 #undef LOAD_PROC
7475 /* Try loading functions not available before XP. */
7476 pfn_getaddrinfo = (void *) GetProcAddress (winsock_lib, "getaddrinfo");
7477 pfn_freeaddrinfo = (void *) GetProcAddress (winsock_lib, "freeaddrinfo");
7478 /* Paranoia: these two functions should go together, so if one
7479 is absent, we cannot use the other. */
7480 if (pfn_getaddrinfo == NULL)
7481 pfn_freeaddrinfo = NULL;
7482 else if (pfn_freeaddrinfo == NULL)
7483 pfn_getaddrinfo = NULL;
7485 /* specify version 1.1 of winsock */
7486 if (pfn_WSAStartup (0x101, &winsockData) == 0)
7488 if (winsockData.wVersion != 0x101)
7489 goto fail;
7491 if (!load_now)
7493 /* Report that winsock exists and is usable, but leave
7494 socket functions disabled. I am assuming that calling
7495 WSAStartup does not require any network interaction,
7496 and in particular does not cause or require a dial-up
7497 connection to be established. */
7499 pfn_WSACleanup ();
7500 FreeLibrary (winsock_lib);
7501 winsock_lib = NULL;
7503 winsock_inuse = 0;
7504 return TRUE;
7507 fail:
7508 FreeLibrary (winsock_lib);
7509 winsock_lib = NULL;
7512 return FALSE;
7516 int h_errno = 0;
7518 /* Function to map winsock error codes to errno codes for those errno
7519 code defined in errno.h (errno values not defined by errno.h are
7520 already in nt/inc/sys/socket.h). */
7521 static void
7522 set_errno (void)
7524 int wsa_err;
7526 h_errno = 0;
7527 if (winsock_lib == NULL)
7528 wsa_err = EINVAL;
7529 else
7530 wsa_err = pfn_WSAGetLastError ();
7532 switch (wsa_err)
7534 case WSAEACCES: errno = EACCES; break;
7535 case WSAEBADF: errno = EBADF; break;
7536 case WSAEFAULT: errno = EFAULT; break;
7537 case WSAEINTR: errno = EINTR; break;
7538 case WSAEINVAL: errno = EINVAL; break;
7539 case WSAEMFILE: errno = EMFILE; break;
7540 case WSAENAMETOOLONG: errno = ENAMETOOLONG; break;
7541 case WSAENOTEMPTY: errno = ENOTEMPTY; break;
7542 case WSAEWOULDBLOCK: errno = EWOULDBLOCK; break;
7543 case WSAENOTCONN: errno = ENOTCONN; break;
7544 default: errno = wsa_err; break;
7548 static void
7549 check_errno (void)
7551 h_errno = 0;
7552 if (winsock_lib != NULL)
7553 pfn_WSASetLastError (0);
7556 /* Extend strerror to handle the winsock-specific error codes. */
7557 struct {
7558 int errnum;
7559 const char * msg;
7560 } _wsa_errlist[] = {
7561 {WSAEINTR , "Interrupted function call"},
7562 {WSAEBADF , "Bad file descriptor"},
7563 {WSAEACCES , "Permission denied"},
7564 {WSAEFAULT , "Bad address"},
7565 {WSAEINVAL , "Invalid argument"},
7566 {WSAEMFILE , "Too many open files"},
7568 {WSAEWOULDBLOCK , "Resource temporarily unavailable"},
7569 {WSAEINPROGRESS , "Operation now in progress"},
7570 {WSAEALREADY , "Operation already in progress"},
7571 {WSAENOTSOCK , "Socket operation on non-socket"},
7572 {WSAEDESTADDRREQ , "Destination address required"},
7573 {WSAEMSGSIZE , "Message too long"},
7574 {WSAEPROTOTYPE , "Protocol wrong type for socket"},
7575 {WSAENOPROTOOPT , "Bad protocol option"},
7576 {WSAEPROTONOSUPPORT , "Protocol not supported"},
7577 {WSAESOCKTNOSUPPORT , "Socket type not supported"},
7578 {WSAEOPNOTSUPP , "Operation not supported"},
7579 {WSAEPFNOSUPPORT , "Protocol family not supported"},
7580 {WSAEAFNOSUPPORT , "Address family not supported by protocol family"},
7581 {WSAEADDRINUSE , "Address already in use"},
7582 {WSAEADDRNOTAVAIL , "Cannot assign requested address"},
7583 {WSAENETDOWN , "Network is down"},
7584 {WSAENETUNREACH , "Network is unreachable"},
7585 {WSAENETRESET , "Network dropped connection on reset"},
7586 {WSAECONNABORTED , "Software caused connection abort"},
7587 {WSAECONNRESET , "Connection reset by peer"},
7588 {WSAENOBUFS , "No buffer space available"},
7589 {WSAEISCONN , "Socket is already connected"},
7590 {WSAENOTCONN , "Socket is not connected"},
7591 {WSAESHUTDOWN , "Cannot send after socket shutdown"},
7592 {WSAETOOMANYREFS , "Too many references"}, /* not sure */
7593 {WSAETIMEDOUT , "Connection timed out"},
7594 {WSAECONNREFUSED , "Connection refused"},
7595 {WSAELOOP , "Network loop"}, /* not sure */
7596 {WSAENAMETOOLONG , "Name is too long"},
7597 {WSAEHOSTDOWN , "Host is down"},
7598 {WSAEHOSTUNREACH , "No route to host"},
7599 {WSAENOTEMPTY , "Buffer not empty"}, /* not sure */
7600 {WSAEPROCLIM , "Too many processes"},
7601 {WSAEUSERS , "Too many users"}, /* not sure */
7602 {WSAEDQUOT , "Double quote in host name"}, /* really not sure */
7603 {WSAESTALE , "Data is stale"}, /* not sure */
7604 {WSAEREMOTE , "Remote error"}, /* not sure */
7606 {WSASYSNOTREADY , "Network subsystem is unavailable"},
7607 {WSAVERNOTSUPPORTED , "WINSOCK.DLL version out of range"},
7608 {WSANOTINITIALISED , "Winsock not initialized successfully"},
7609 {WSAEDISCON , "Graceful shutdown in progress"},
7610 #ifdef WSAENOMORE
7611 {WSAENOMORE , "No more operations allowed"}, /* not sure */
7612 {WSAECANCELLED , "Operation cancelled"}, /* not sure */
7613 {WSAEINVALIDPROCTABLE , "Invalid procedure table from service provider"},
7614 {WSAEINVALIDPROVIDER , "Invalid service provider version number"},
7615 {WSAEPROVIDERFAILEDINIT , "Unable to initialize a service provider"},
7616 {WSASYSCALLFAILURE , "System call failure"},
7617 {WSASERVICE_NOT_FOUND , "Service not found"}, /* not sure */
7618 {WSATYPE_NOT_FOUND , "Class type not found"},
7619 {WSA_E_NO_MORE , "No more resources available"}, /* really not sure */
7620 {WSA_E_CANCELLED , "Operation already cancelled"}, /* really not sure */
7621 {WSAEREFUSED , "Operation refused"}, /* not sure */
7622 #endif
7624 {WSAHOST_NOT_FOUND , "Host not found"},
7625 {WSATRY_AGAIN , "Authoritative host not found during name lookup"},
7626 {WSANO_RECOVERY , "Non-recoverable error during name lookup"},
7627 {WSANO_DATA , "Valid name, no data record of requested type"},
7629 {-1, NULL}
7632 char *
7633 sys_strerror (int error_no)
7635 int i;
7636 static char unknown_msg[40];
7638 if (error_no >= 0 && error_no < sys_nerr)
7639 return sys_errlist[error_no];
7641 for (i = 0; _wsa_errlist[i].errnum >= 0; i++)
7642 if (_wsa_errlist[i].errnum == error_no)
7643 return (char *)_wsa_errlist[i].msg;
7645 sprintf (unknown_msg, "Unidentified error: %d", error_no);
7646 return unknown_msg;
7649 /* [andrewi 3-May-96] I've had conflicting results using both methods,
7650 but I believe the method of keeping the socket handle separate (and
7651 insuring it is not inheritable) is the correct one. */
7653 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
7655 static int socket_to_fd (SOCKET s);
7658 sys_socket (int af, int type, int protocol)
7660 SOCKET s;
7662 if (winsock_lib == NULL)
7664 errno = ENETDOWN;
7665 return -1;
7668 check_errno ();
7670 /* call the real socket function */
7671 s = pfn_socket (af, type, protocol);
7673 if (s != INVALID_SOCKET)
7674 return socket_to_fd (s);
7676 set_errno ();
7677 return -1;
7680 /* Convert a SOCKET to a file descriptor. */
7681 static int
7682 socket_to_fd (SOCKET s)
7684 int fd;
7685 child_process * cp;
7687 /* Although under NT 3.5 _open_osfhandle will accept a socket
7688 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
7689 that does not work under NT 3.1. However, we can get the same
7690 effect by using a backdoor function to replace an existing
7691 descriptor handle with the one we want. */
7693 /* allocate a file descriptor (with appropriate flags) */
7694 fd = _open ("NUL:", _O_RDWR);
7695 if (fd >= 0)
7697 /* Make a non-inheritable copy of the socket handle. Note
7698 that it is possible that sockets aren't actually kernel
7699 handles, which appears to be the case on Windows 9x when
7700 the MS Proxy winsock client is installed. */
7702 /* Apparently there is a bug in NT 3.51 with some service
7703 packs, which prevents using DuplicateHandle to make a
7704 socket handle non-inheritable (causes WSACleanup to
7705 hang). The work-around is to use SetHandleInformation
7706 instead if it is available and implemented. */
7707 if (pfn_SetHandleInformation)
7709 pfn_SetHandleInformation ((HANDLE) s, HANDLE_FLAG_INHERIT, 0);
7711 else
7713 HANDLE parent = GetCurrentProcess ();
7714 HANDLE new_s = INVALID_HANDLE_VALUE;
7716 if (DuplicateHandle (parent,
7717 (HANDLE) s,
7718 parent,
7719 &new_s,
7721 FALSE,
7722 DUPLICATE_SAME_ACCESS))
7724 /* It is possible that DuplicateHandle succeeds even
7725 though the socket wasn't really a kernel handle,
7726 because a real handle has the same value. So
7727 test whether the new handle really is a socket. */
7728 unsigned long nonblocking = 0;
7729 if (pfn_ioctlsocket ((SOCKET) new_s, FIONBIO, &nonblocking) == 0)
7731 pfn_closesocket (s);
7732 s = (SOCKET) new_s;
7734 else
7736 CloseHandle (new_s);
7741 eassert (fd < MAXDESC);
7742 fd_info[fd].hnd = (HANDLE) s;
7744 /* set our own internal flags */
7745 fd_info[fd].flags = FILE_SOCKET | FILE_BINARY | FILE_READ | FILE_WRITE;
7747 cp = new_child ();
7748 if (cp)
7750 cp->fd = fd;
7751 cp->status = STATUS_READ_ACKNOWLEDGED;
7753 /* attach child_process to fd_info */
7754 if (fd_info[ fd ].cp != NULL)
7756 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd));
7757 emacs_abort ();
7760 fd_info[ fd ].cp = cp;
7762 /* success! */
7763 winsock_inuse++; /* count open sockets */
7764 return fd;
7767 /* clean up */
7768 _close (fd);
7770 else
7771 pfn_closesocket (s);
7772 errno = EMFILE;
7773 return -1;
7777 sys_bind (int s, const struct sockaddr * addr, int namelen)
7779 if (winsock_lib == NULL)
7781 errno = ENOTSOCK;
7782 return SOCKET_ERROR;
7785 check_errno ();
7786 if (fd_info[s].flags & FILE_SOCKET)
7788 int rc = pfn_bind (SOCK_HANDLE (s), addr, namelen);
7789 if (rc == SOCKET_ERROR)
7790 set_errno ();
7791 return rc;
7793 errno = ENOTSOCK;
7794 return SOCKET_ERROR;
7798 sys_connect (int s, const struct sockaddr * name, int namelen)
7800 if (winsock_lib == NULL)
7802 errno = ENOTSOCK;
7803 return SOCKET_ERROR;
7806 check_errno ();
7807 if (fd_info[s].flags & FILE_SOCKET)
7809 int rc = pfn_connect (SOCK_HANDLE (s), name, namelen);
7810 if (rc == SOCKET_ERROR)
7812 set_errno ();
7813 /* If this is a non-blocking 'connect', set the bit in flags
7814 that will tell reader_thread to wait for connection
7815 before trying to read. */
7816 if (errno == EWOULDBLOCK && (fd_info[s].flags & FILE_NDELAY) != 0)
7818 errno = EINPROGRESS; /* that's what process.c expects */
7819 fd_info[s].flags |= FILE_CONNECT;
7822 return rc;
7824 errno = ENOTSOCK;
7825 return SOCKET_ERROR;
7828 u_short
7829 sys_htons (u_short hostshort)
7831 return (winsock_lib != NULL) ?
7832 pfn_htons (hostshort) : hostshort;
7835 u_short
7836 sys_ntohs (u_short netshort)
7838 return (winsock_lib != NULL) ?
7839 pfn_ntohs (netshort) : netshort;
7842 unsigned long
7843 sys_inet_addr (const char * cp)
7845 return (winsock_lib != NULL) ?
7846 pfn_inet_addr (cp) : INADDR_NONE;
7850 sys_gethostname (char * name, int namelen)
7852 if (winsock_lib != NULL)
7854 int retval;
7856 check_errno ();
7857 retval = pfn_gethostname (name, namelen);
7858 if (retval == SOCKET_ERROR)
7859 set_errno ();
7860 return retval;
7863 if (namelen > MAX_COMPUTERNAME_LENGTH)
7864 return !GetComputerName (name, (DWORD *)&namelen);
7866 errno = EFAULT;
7867 return SOCKET_ERROR;
7870 struct hostent *
7871 sys_gethostbyname (const char * name)
7873 struct hostent * host;
7874 int h_err = h_errno;
7876 if (winsock_lib == NULL)
7878 h_errno = NO_RECOVERY;
7879 errno = ENETDOWN;
7880 return NULL;
7883 check_errno ();
7884 host = pfn_gethostbyname (name);
7885 if (!host)
7887 set_errno ();
7888 h_errno = errno;
7890 else
7891 h_errno = h_err;
7892 return host;
7895 struct servent *
7896 sys_getservbyname (const char * name, const char * proto)
7898 struct servent * serv;
7900 if (winsock_lib == NULL)
7902 errno = ENETDOWN;
7903 return NULL;
7906 check_errno ();
7907 serv = pfn_getservbyname (name, proto);
7908 if (!serv)
7909 set_errno ();
7910 return serv;
7914 sys_getpeername (int s, struct sockaddr *addr, int * namelen)
7916 if (winsock_lib == NULL)
7918 errno = ENETDOWN;
7919 return SOCKET_ERROR;
7922 check_errno ();
7923 if (fd_info[s].flags & FILE_SOCKET)
7925 int rc = pfn_getpeername (SOCK_HANDLE (s), addr, namelen);
7926 if (rc == SOCKET_ERROR)
7927 set_errno ();
7928 return rc;
7930 errno = ENOTSOCK;
7931 return SOCKET_ERROR;
7935 sys_getaddrinfo (const char *node, const char *service,
7936 const struct addrinfo *hints, struct addrinfo **res)
7938 int rc;
7940 if (winsock_lib == NULL)
7942 errno = ENETDOWN;
7943 return SOCKET_ERROR;
7946 check_errno ();
7947 if (pfn_getaddrinfo)
7948 rc = pfn_getaddrinfo (node, service, hints, res);
7949 else
7951 int port = 0;
7952 struct hostent *host_info;
7953 struct gai_storage {
7954 struct addrinfo addrinfo;
7955 struct sockaddr_in sockaddr_in;
7956 } *gai_storage;
7958 /* We don't (yet) support any flags, as Emacs doesn't need that. */
7959 if (hints && hints->ai_flags != 0)
7960 return WSAEINVAL;
7961 /* NODE cannot be NULL, since process.c has fallbacks for that. */
7962 if (!node)
7963 return WSAHOST_NOT_FOUND;
7965 if (service)
7967 const char *protocol =
7968 (hints && hints->ai_socktype == SOCK_DGRAM) ? "udp" : "tcp";
7969 struct servent *srv = sys_getservbyname (service, protocol);
7971 if (srv)
7972 port = srv->s_port;
7973 else if (*service >= '0' && *service <= '9')
7975 char *endp;
7977 port = strtoul (service, &endp, 10);
7978 if (*endp || port > 65536)
7979 return WSAHOST_NOT_FOUND;
7980 port = sys_htons ((unsigned short) port);
7982 else
7983 return WSAHOST_NOT_FOUND;
7986 gai_storage = xzalloc (sizeof *gai_storage);
7987 gai_storage->sockaddr_in.sin_port = port;
7988 host_info = sys_gethostbyname (node);
7989 if (host_info)
7991 memcpy (&gai_storage->sockaddr_in.sin_addr,
7992 host_info->h_addr, host_info->h_length);
7993 gai_storage->sockaddr_in.sin_family = host_info->h_addrtype;
7995 else
7997 /* Attempt to interpret host as numeric inet address. */
7998 unsigned long numeric_addr = sys_inet_addr (node);
8000 if (numeric_addr == -1)
8002 free (gai_storage);
8003 return WSAHOST_NOT_FOUND;
8006 memcpy (&gai_storage->sockaddr_in.sin_addr, &numeric_addr,
8007 sizeof (gai_storage->sockaddr_in.sin_addr));
8008 gai_storage->sockaddr_in.sin_family = (hints) ? hints->ai_family : 0;
8011 gai_storage->addrinfo.ai_addr =
8012 (struct sockaddr *)&gai_storage->sockaddr_in;
8013 gai_storage->addrinfo.ai_addrlen = sizeof (gai_storage->sockaddr_in);
8014 gai_storage->addrinfo.ai_protocol = (hints) ? hints->ai_protocol : 0;
8015 gai_storage->addrinfo.ai_socktype = (hints) ? hints->ai_socktype : 0;
8016 gai_storage->addrinfo.ai_family = gai_storage->sockaddr_in.sin_family;
8017 gai_storage->addrinfo.ai_next = NULL;
8019 *res = &gai_storage->addrinfo;
8020 rc = 0;
8023 return rc;
8026 void
8027 sys_freeaddrinfo (struct addrinfo *ai)
8029 if (winsock_lib == NULL)
8031 errno = ENETDOWN;
8032 return;
8035 check_errno ();
8036 if (pfn_freeaddrinfo)
8037 pfn_freeaddrinfo (ai);
8038 else
8040 eassert (ai->ai_next == NULL);
8041 xfree (ai);
8046 sys_shutdown (int s, int how)
8048 if (winsock_lib == NULL)
8050 errno = ENETDOWN;
8051 return SOCKET_ERROR;
8054 check_errno ();
8055 if (fd_info[s].flags & FILE_SOCKET)
8057 int rc = pfn_shutdown (SOCK_HANDLE (s), how);
8058 if (rc == SOCKET_ERROR)
8059 set_errno ();
8060 return rc;
8062 errno = ENOTSOCK;
8063 return SOCKET_ERROR;
8067 sys_setsockopt (int s, int level, int optname, const void * optval, int optlen)
8069 if (winsock_lib == NULL)
8071 errno = ENETDOWN;
8072 return SOCKET_ERROR;
8075 check_errno ();
8076 if (fd_info[s].flags & FILE_SOCKET)
8078 int rc = pfn_setsockopt (SOCK_HANDLE (s), level, optname,
8079 (const char *)optval, optlen);
8080 if (rc == SOCKET_ERROR)
8081 set_errno ();
8082 return rc;
8084 errno = ENOTSOCK;
8085 return SOCKET_ERROR;
8089 sys_listen (int s, int backlog)
8091 if (winsock_lib == NULL)
8093 errno = ENETDOWN;
8094 return SOCKET_ERROR;
8097 check_errno ();
8098 if (fd_info[s].flags & FILE_SOCKET)
8100 int rc = pfn_listen (SOCK_HANDLE (s), backlog);
8101 if (rc == SOCKET_ERROR)
8102 set_errno ();
8103 else
8104 fd_info[s].flags |= FILE_LISTEN;
8105 return rc;
8107 errno = ENOTSOCK;
8108 return SOCKET_ERROR;
8112 sys_getsockname (int s, struct sockaddr * name, int * namelen)
8114 if (winsock_lib == NULL)
8116 errno = ENETDOWN;
8117 return SOCKET_ERROR;
8120 check_errno ();
8121 if (fd_info[s].flags & FILE_SOCKET)
8123 int rc = pfn_getsockname (SOCK_HANDLE (s), name, namelen);
8124 if (rc == SOCKET_ERROR)
8125 set_errno ();
8126 return rc;
8128 errno = ENOTSOCK;
8129 return SOCKET_ERROR;
8133 sys_accept (int s, struct sockaddr * addr, int * addrlen)
8135 if (winsock_lib == NULL)
8137 errno = ENETDOWN;
8138 return -1;
8141 check_errno ();
8142 if (fd_info[s].flags & FILE_LISTEN)
8144 SOCKET t = pfn_accept (SOCK_HANDLE (s), addr, addrlen);
8145 int fd = -1;
8146 if (t == INVALID_SOCKET)
8147 set_errno ();
8148 else
8149 fd = socket_to_fd (t);
8151 if (fd >= 0)
8153 fd_info[s].cp->status = STATUS_READ_ACKNOWLEDGED;
8154 ResetEvent (fd_info[s].cp->char_avail);
8156 return fd;
8158 errno = ENOTSOCK;
8159 return -1;
8163 sys_recvfrom (int s, char * buf, int len, int flags,
8164 struct sockaddr * from, int * fromlen)
8166 if (winsock_lib == NULL)
8168 errno = ENETDOWN;
8169 return SOCKET_ERROR;
8172 check_errno ();
8173 if (fd_info[s].flags & FILE_SOCKET)
8175 int rc = pfn_recvfrom (SOCK_HANDLE (s), buf, len, flags, from, fromlen);
8176 if (rc == SOCKET_ERROR)
8177 set_errno ();
8178 return rc;
8180 errno = ENOTSOCK;
8181 return SOCKET_ERROR;
8185 sys_sendto (int s, const char * buf, int len, int flags,
8186 const struct sockaddr * to, int tolen)
8188 if (winsock_lib == NULL)
8190 errno = ENETDOWN;
8191 return SOCKET_ERROR;
8194 check_errno ();
8195 if (fd_info[s].flags & FILE_SOCKET)
8197 int rc = pfn_sendto (SOCK_HANDLE (s), buf, len, flags, to, tolen);
8198 if (rc == SOCKET_ERROR)
8199 set_errno ();
8200 return rc;
8202 errno = ENOTSOCK;
8203 return SOCKET_ERROR;
8206 /* Windows does not have an fcntl function. Provide an implementation
8207 good enough for Emacs. */
8209 fcntl (int s, int cmd, int options)
8211 /* In the w32 Emacs port, fcntl (fd, F_DUPFD_CLOEXEC, fd1) is always
8212 invoked in a context where fd1 is closed and all descriptors less
8213 than fd1 are open, so sys_dup is an adequate implementation. */
8214 if (cmd == F_DUPFD_CLOEXEC)
8215 return sys_dup (s);
8217 check_errno ();
8218 if (fd_info[s].flags & FILE_SOCKET)
8220 if (winsock_lib == NULL)
8222 errno = ENETDOWN;
8223 return -1;
8226 if (cmd == F_SETFL && options == O_NONBLOCK)
8228 unsigned long nblock = 1;
8229 int rc = pfn_ioctlsocket (SOCK_HANDLE (s), FIONBIO, &nblock);
8230 if (rc == SOCKET_ERROR)
8231 set_errno ();
8232 /* Keep track of the fact that we set this to non-blocking. */
8233 fd_info[s].flags |= FILE_NDELAY;
8234 return rc;
8236 else
8238 errno = EINVAL;
8239 return SOCKET_ERROR;
8242 else if ((fd_info[s].flags & (FILE_PIPE | FILE_WRITE))
8243 == (FILE_PIPE | FILE_WRITE))
8245 /* Force our writes to pipes be non-blocking. */
8246 if (cmd == F_SETFL && options == O_NONBLOCK)
8248 HANDLE h = (HANDLE)_get_osfhandle (s);
8249 DWORD pipe_mode = PIPE_NOWAIT;
8251 if (!SetNamedPipeHandleState (h, &pipe_mode, NULL, NULL))
8253 DebPrint (("SetNamedPipeHandleState: %lu\n", GetLastError ()));
8254 return SOCKET_ERROR;
8256 fd_info[s].flags |= FILE_NDELAY;
8257 return 0;
8259 else
8261 errno = EINVAL;
8262 return SOCKET_ERROR;
8265 errno = ENOTSOCK;
8266 return SOCKET_ERROR;
8270 /* Shadow main io functions: we need to handle pipes and sockets more
8271 intelligently. */
8274 sys_close (int fd)
8276 int rc;
8278 if (fd < 0)
8280 errno = EBADF;
8281 return -1;
8284 if (fd < MAXDESC && fd_info[fd].cp)
8286 child_process * cp = fd_info[fd].cp;
8288 fd_info[fd].cp = NULL;
8290 if (CHILD_ACTIVE (cp))
8292 /* if last descriptor to active child_process then cleanup */
8293 int i;
8294 for (i = 0; i < MAXDESC; i++)
8296 if (i == fd)
8297 continue;
8298 if (fd_info[i].cp == cp)
8299 break;
8301 if (i == MAXDESC)
8303 if (fd_info[fd].flags & FILE_SOCKET)
8305 if (winsock_lib == NULL) emacs_abort ();
8307 pfn_shutdown (SOCK_HANDLE (fd), 2);
8308 rc = pfn_closesocket (SOCK_HANDLE (fd));
8310 winsock_inuse--; /* count open sockets */
8312 /* If the process handle is NULL, it's either a socket
8313 or serial connection, or a subprocess that was
8314 already reaped by reap_subprocess, but whose
8315 resources were not yet freed, because its output was
8316 not fully read yet by the time it was reaped. (This
8317 usually happens with async subprocesses whose output
8318 is being read by Emacs.) Otherwise, this process was
8319 not reaped yet, so we set its FD to a negative value
8320 to make sure sys_select will eventually get to
8321 calling the SIGCHLD handler for it, which will then
8322 invoke waitpid and reap_subprocess. */
8323 if (cp->procinfo.hProcess == NULL)
8324 delete_child (cp);
8325 else
8326 cp->fd = -1;
8331 if (fd >= 0 && fd < MAXDESC)
8332 fd_info[fd].flags = 0;
8334 /* Note that sockets do not need special treatment here (at least on
8335 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
8336 closesocket is equivalent to CloseHandle, which is to be expected
8337 because socket handles are fully fledged kernel handles. */
8338 rc = _close (fd);
8340 return rc;
8344 sys_dup (int fd)
8346 int new_fd;
8348 new_fd = _dup (fd);
8349 if (new_fd >= 0 && new_fd < MAXDESC)
8351 /* duplicate our internal info as well */
8352 fd_info[new_fd] = fd_info[fd];
8354 return new_fd;
8358 sys_dup2 (int src, int dst)
8360 int rc;
8362 if (dst < 0 || dst >= MAXDESC)
8364 errno = EBADF;
8365 return -1;
8368 /* MS _dup2 seems to have weird side effect when invoked with 2
8369 identical arguments: an attempt to fclose the corresponding stdio
8370 stream after that hangs (we do close standard streams in
8371 init_ntproc). Attempt to avoid that by not calling _dup2 that
8372 way: if SRC is valid, we know that dup2 should be a no-op, so do
8373 nothing and return DST. */
8374 if (src == dst)
8376 if ((HANDLE)_get_osfhandle (src) == INVALID_HANDLE_VALUE)
8378 errno = EBADF;
8379 return -1;
8381 return dst;
8384 /* Make sure we close the destination first if it's a pipe or socket. */
8385 if (fd_info[dst].flags != 0)
8386 sys_close (dst);
8388 rc = _dup2 (src, dst);
8389 if (rc == 0)
8391 /* Duplicate our internal info as well. */
8392 fd_info[dst] = fd_info[src];
8394 return rc == 0 ? dst : rc;
8398 pipe2 (int * phandles, int pipe2_flags)
8400 int rc;
8401 unsigned flags;
8402 unsigned pipe_size = 0;
8404 eassert (pipe2_flags == (O_BINARY | O_CLOEXEC));
8406 /* Allow Lisp to override the default buffer size of the pipe. */
8407 if (w32_pipe_buffer_size > 0 && w32_pipe_buffer_size < UINT_MAX)
8408 pipe_size = w32_pipe_buffer_size;
8410 /* make pipe handles non-inheritable; when we spawn a child, we
8411 replace the relevant handle with an inheritable one. Also put
8412 pipes into binary mode; we will do text mode translation ourselves
8413 if required. */
8414 rc = _pipe (phandles, pipe_size, _O_NOINHERIT | _O_BINARY);
8416 if (rc == 0)
8418 /* Protect against overflow, since Windows can open more handles than
8419 our fd_info array has room for. */
8420 if (phandles[0] >= MAXDESC || phandles[1] >= MAXDESC)
8422 _close (phandles[0]);
8423 _close (phandles[1]);
8424 errno = EMFILE;
8425 rc = -1;
8427 else
8429 flags = FILE_PIPE | FILE_READ | FILE_BINARY;
8430 fd_info[phandles[0]].flags = flags;
8432 flags = FILE_PIPE | FILE_WRITE | FILE_BINARY;
8433 fd_info[phandles[1]].flags = flags;
8437 return rc;
8440 /* Function to do blocking read of one byte, needed to implement
8441 select. It is only allowed on communication ports, sockets, or
8442 pipes. */
8444 _sys_read_ahead (int fd)
8446 child_process * cp;
8447 int rc;
8449 if (fd < 0 || fd >= MAXDESC)
8450 return STATUS_READ_ERROR;
8452 cp = fd_info[fd].cp;
8454 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
8455 return STATUS_READ_ERROR;
8457 if ((fd_info[fd].flags & (FILE_PIPE | FILE_SERIAL | FILE_SOCKET)) == 0
8458 || (fd_info[fd].flags & FILE_READ) == 0)
8460 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd));
8461 emacs_abort ();
8464 if ((fd_info[fd].flags & FILE_CONNECT) != 0)
8465 DebPrint (("_sys_read_ahead: read requested from fd %d, which waits for async connect!\n", fd));
8466 cp->status = STATUS_READ_IN_PROGRESS;
8468 if (fd_info[fd].flags & FILE_PIPE)
8470 rc = _read (fd, &cp->chr, sizeof (char));
8472 /* Give subprocess time to buffer some more output for us before
8473 reporting that input is available; we need this because Windows 95
8474 connects DOS programs to pipes by making the pipe appear to be
8475 the normal console stdout - as a result most DOS programs will
8476 write to stdout without buffering, ie. one character at a
8477 time. Even some W32 programs do this - "dir" in a command
8478 shell on NT is very slow if we don't do this. */
8479 if (rc > 0)
8481 int wait = w32_pipe_read_delay;
8483 if (wait > 0)
8484 Sleep (wait);
8485 else if (wait < 0)
8486 while (++wait <= 0)
8487 /* Yield remainder of our time slice, effectively giving a
8488 temporary priority boost to the child process. */
8489 Sleep (0);
8492 else if (fd_info[fd].flags & FILE_SERIAL)
8494 HANDLE hnd = fd_info[fd].hnd;
8495 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
8496 COMMTIMEOUTS ct;
8498 /* Configure timeouts for blocking read. */
8499 if (!GetCommTimeouts (hnd, &ct))
8501 cp->status = STATUS_READ_ERROR;
8502 return STATUS_READ_ERROR;
8504 ct.ReadIntervalTimeout = 0;
8505 ct.ReadTotalTimeoutMultiplier = 0;
8506 ct.ReadTotalTimeoutConstant = 0;
8507 if (!SetCommTimeouts (hnd, &ct))
8509 cp->status = STATUS_READ_ERROR;
8510 return STATUS_READ_ERROR;
8513 if (!ReadFile (hnd, &cp->chr, sizeof (char), (DWORD*) &rc, ovl))
8515 if (GetLastError () != ERROR_IO_PENDING)
8517 cp->status = STATUS_READ_ERROR;
8518 return STATUS_READ_ERROR;
8520 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
8522 cp->status = STATUS_READ_ERROR;
8523 return STATUS_READ_ERROR;
8527 else if (fd_info[fd].flags & FILE_SOCKET)
8529 unsigned long nblock = 0;
8530 /* We always want this to block, so temporarily disable NDELAY. */
8531 if (fd_info[fd].flags & FILE_NDELAY)
8532 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
8534 rc = pfn_recv (SOCK_HANDLE (fd), &cp->chr, sizeof (char), 0);
8536 if (fd_info[fd].flags & FILE_NDELAY)
8538 nblock = 1;
8539 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
8543 if (rc == sizeof (char))
8544 cp->status = STATUS_READ_SUCCEEDED;
8545 else
8546 cp->status = STATUS_READ_FAILED;
8548 return cp->status;
8552 _sys_wait_accept (int fd)
8554 HANDLE hEv;
8555 child_process * cp;
8556 int rc;
8558 if (fd < 0 || fd >= MAXDESC)
8559 return STATUS_READ_ERROR;
8561 cp = fd_info[fd].cp;
8563 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
8564 return STATUS_READ_ERROR;
8566 cp->status = STATUS_READ_FAILED;
8568 hEv = pfn_WSACreateEvent ();
8569 rc = pfn_WSAEventSelect (SOCK_HANDLE (fd), hEv, FD_ACCEPT);
8570 if (rc != SOCKET_ERROR)
8572 do {
8573 rc = WaitForSingleObject (hEv, 500);
8574 Sleep (5);
8575 } while (rc == WAIT_TIMEOUT
8576 && cp->status != STATUS_READ_ERROR
8577 && cp->char_avail);
8578 pfn_WSAEventSelect (SOCK_HANDLE (fd), NULL, 0);
8579 if (rc == WAIT_OBJECT_0)
8580 cp->status = STATUS_READ_SUCCEEDED;
8582 pfn_WSACloseEvent (hEv);
8584 return cp->status;
8588 _sys_wait_connect (int fd)
8590 HANDLE hEv;
8591 child_process * cp;
8592 int rc;
8594 if (fd < 0 || fd >= MAXDESC)
8595 return STATUS_READ_ERROR;
8597 cp = fd_info[fd].cp;
8598 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
8599 return STATUS_READ_ERROR;
8601 cp->status = STATUS_READ_FAILED;
8603 hEv = pfn_WSACreateEvent ();
8604 rc = pfn_WSAEventSelect (SOCK_HANDLE (fd), hEv, FD_CONNECT);
8605 if (rc != SOCKET_ERROR)
8607 do {
8608 rc = WaitForSingleObject (hEv, 500);
8609 Sleep (5);
8610 } while (rc == WAIT_TIMEOUT
8611 && cp->status != STATUS_READ_ERROR
8612 && cp->char_avail);
8613 if (rc == WAIT_OBJECT_0)
8615 /* We've got an event, but it could be a successful
8616 connection, or it could be a failure. Find out
8617 which one is it. */
8618 WSANETWORKEVENTS events;
8620 pfn_WSAEnumNetworkEvents (SOCK_HANDLE (fd), hEv, &events);
8621 if ((events.lNetworkEvents & FD_CONNECT) != 0
8622 && events.iErrorCode[FD_CONNECT_BIT])
8624 cp->status = STATUS_CONNECT_FAILED;
8625 cp->errcode = events.iErrorCode[FD_CONNECT_BIT];
8627 else
8629 cp->status = STATUS_READ_SUCCEEDED;
8630 cp->errcode = 0;
8633 pfn_WSAEventSelect (SOCK_HANDLE (fd), NULL, 0);
8635 else
8636 pfn_WSACloseEvent (hEv);
8638 return cp->status;
8642 sys_read (int fd, char * buffer, unsigned int count)
8644 int nchars;
8645 int to_read;
8646 DWORD waiting;
8647 char * orig_buffer = buffer;
8649 if (fd < 0)
8651 errno = EBADF;
8652 return -1;
8655 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
8657 child_process *cp = fd_info[fd].cp;
8659 if ((fd_info[fd].flags & FILE_READ) == 0)
8661 errno = EBADF;
8662 return -1;
8665 nchars = 0;
8667 /* re-read CR carried over from last read */
8668 if (fd_info[fd].flags & FILE_LAST_CR)
8670 if (fd_info[fd].flags & FILE_BINARY) emacs_abort ();
8671 *buffer++ = 0x0d;
8672 count--;
8673 nchars++;
8674 fd_info[fd].flags &= ~FILE_LAST_CR;
8677 /* presence of a child_process structure means we are operating in
8678 non-blocking mode - otherwise we just call _read directly.
8679 Note that the child_process structure might be missing because
8680 reap_subprocess has been called; in this case the pipe is
8681 already broken, so calling _read on it is okay. */
8682 if (cp)
8684 int current_status = cp->status;
8686 switch (current_status)
8688 case STATUS_READ_FAILED:
8689 case STATUS_READ_ERROR:
8690 /* report normal EOF if nothing in buffer */
8691 if (nchars <= 0)
8692 fd_info[fd].flags |= FILE_AT_EOF;
8693 return nchars;
8695 case STATUS_READ_READY:
8696 case STATUS_READ_IN_PROGRESS:
8697 #if 0
8698 /* This happens all the time during GnuTLS handshake
8699 with the remote, evidently because GnuTLS waits for
8700 the read to complete by retrying the read operation
8701 upon EAGAIN. So I'm disabling the DebPrint to avoid
8702 wasting cycles on something that is not a real
8703 problem. Enable if you need to debug something that
8704 bumps into this. */
8705 DebPrint (("sys_read called when read is in progress %d\n",
8706 current_status));
8707 #endif
8708 errno = EWOULDBLOCK;
8709 return -1;
8711 case STATUS_READ_SUCCEEDED:
8712 /* consume read-ahead char */
8713 *buffer++ = cp->chr;
8714 count--;
8715 nchars++;
8716 cp->status = STATUS_READ_ACKNOWLEDGED;
8717 ResetEvent (cp->char_avail);
8719 case STATUS_READ_ACKNOWLEDGED:
8720 case STATUS_CONNECT_FAILED:
8721 break;
8723 default:
8724 DebPrint (("sys_read: bad status %d\n", current_status));
8725 errno = EBADF;
8726 return -1;
8729 if (fd_info[fd].flags & FILE_PIPE)
8731 PeekNamedPipe ((HANDLE) _get_osfhandle (fd), NULL, 0, NULL, &waiting, NULL);
8732 to_read = min (waiting, (DWORD) count);
8734 if (to_read > 0)
8735 nchars += _read (fd, buffer, to_read);
8737 else if (fd_info[fd].flags & FILE_SERIAL)
8739 HANDLE hnd = fd_info[fd].hnd;
8740 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
8741 int rc = 0;
8742 COMMTIMEOUTS ct;
8744 if (count > 0)
8746 /* Configure timeouts for non-blocking read. */
8747 if (!GetCommTimeouts (hnd, &ct))
8749 errno = EIO;
8750 return -1;
8752 ct.ReadIntervalTimeout = MAXDWORD;
8753 ct.ReadTotalTimeoutMultiplier = 0;
8754 ct.ReadTotalTimeoutConstant = 0;
8755 if (!SetCommTimeouts (hnd, &ct))
8757 errno = EIO;
8758 return -1;
8761 if (!ResetEvent (ovl->hEvent))
8763 errno = EIO;
8764 return -1;
8766 if (!ReadFile (hnd, buffer, count, (DWORD*) &rc, ovl))
8768 if (GetLastError () != ERROR_IO_PENDING)
8770 errno = EIO;
8771 return -1;
8773 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
8775 errno = EIO;
8776 return -1;
8779 nchars += rc;
8782 else /* FILE_SOCKET */
8784 if (winsock_lib == NULL) emacs_abort ();
8786 /* When a non-blocking 'connect' call fails,
8787 wait_reading_process_output detects this by calling
8788 'getpeername', and then attempts to obtain the connection
8789 error code by trying to read 1 byte from the socket. If
8790 we try to serve that read by calling 'recv' below, the
8791 error we get is a generic WSAENOTCONN, not the actual
8792 connection error. So instead, we use the actual error
8793 code stashed by '_sys_wait_connect' in cp->errcode.
8794 Alternatively, we could have used 'getsockopt', like on
8795 GNU/Linux, but: (a) I have no idea whether the winsock
8796 version could hang, as it does "on some systems" (see the
8797 comment in process.c); and (b) 'getsockopt' on Windows is
8798 documented to clear the socket error for the entire
8799 process, which I'm not sure is TRT; FIXME. */
8800 if (current_status == STATUS_CONNECT_FAILED
8801 && (fd_info[fd].flags & FILE_CONNECT) != 0
8802 && cp->errcode != 0)
8804 pfn_WSASetLastError (cp->errcode);
8805 set_errno ();
8806 return -1;
8808 /* Do the equivalent of a non-blocking read. */
8809 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONREAD, &waiting);
8810 if (waiting == 0 && nchars == 0)
8812 errno = EWOULDBLOCK;
8813 return -1;
8816 if (waiting)
8818 /* always use binary mode for sockets */
8819 int res = pfn_recv (SOCK_HANDLE (fd), buffer, count, 0);
8820 if (res == SOCKET_ERROR)
8822 set_errno ();
8823 DebPrint (("sys_read.recv failed with error %d on socket %ld\n",
8824 errno, SOCK_HANDLE (fd)));
8825 return -1;
8827 nchars += res;
8831 else
8833 int nread = _read (fd, buffer, count);
8834 if (nread >= 0)
8835 nchars += nread;
8836 else if (nchars == 0)
8837 nchars = nread;
8840 if (nchars <= 0)
8841 fd_info[fd].flags |= FILE_AT_EOF;
8842 /* Perform text mode translation if required. */
8843 else if ((fd_info[fd].flags & FILE_BINARY) == 0)
8845 nchars = crlf_to_lf (nchars, orig_buffer);
8846 /* If buffer contains only CR, return that. To be absolutely
8847 sure we should attempt to read the next char, but in
8848 practice a CR to be followed by LF would not appear by
8849 itself in the buffer. */
8850 if (nchars > 1 && orig_buffer[nchars - 1] == 0x0d)
8852 fd_info[fd].flags |= FILE_LAST_CR;
8853 nchars--;
8857 else
8858 nchars = _read (fd, buffer, count);
8860 return nchars;
8863 /* From w32xfns.c */
8864 extern HANDLE interrupt_handle;
8867 sys_write (int fd, const void * buffer, unsigned int count)
8869 int nchars;
8870 USE_SAFE_ALLOCA;
8872 if (fd < 0)
8874 errno = EBADF;
8875 return -1;
8878 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
8880 if ((fd_info[fd].flags & FILE_WRITE) == 0)
8882 errno = EBADF;
8883 return -1;
8886 /* Perform text mode translation if required. */
8887 if ((fd_info[fd].flags & FILE_BINARY) == 0)
8889 char * tmpbuf;
8890 const unsigned char * src = buffer;
8891 unsigned char * dst;
8892 int nbytes = count;
8894 SAFE_NALLOCA (tmpbuf, 2, count);
8895 dst = (unsigned char *)tmpbuf;
8897 while (1)
8899 unsigned char *next;
8900 /* Copy next line or remaining bytes. */
8901 next = _memccpy (dst, src, '\n', nbytes);
8902 if (next)
8904 /* Copied one line ending with '\n'. */
8905 int copied = next - dst;
8906 nbytes -= copied;
8907 src += copied;
8908 /* Insert '\r' before '\n'. */
8909 next[-1] = '\r';
8910 next[0] = '\n';
8911 dst = next + 1;
8912 count++;
8914 else
8915 /* Copied remaining partial line -> now finished. */
8916 break;
8918 buffer = tmpbuf;
8922 if (fd < MAXDESC && fd_info[fd].flags & FILE_SERIAL)
8924 HANDLE hnd = (HANDLE) _get_osfhandle (fd);
8925 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_write;
8926 HANDLE wait_hnd[2] = { interrupt_handle, ovl->hEvent };
8927 DWORD active = 0;
8929 /* This is async (a.k.a. "overlapped") I/O, so the return value
8930 of FALSE from WriteFile means either an error or the output
8931 will be completed asynchronously (ERROR_IO_PENDING). */
8932 if (!WriteFile (hnd, buffer, count, (DWORD*) &nchars, ovl))
8934 if (GetLastError () != ERROR_IO_PENDING)
8936 errno = EIO;
8937 nchars = -1;
8939 else
8941 /* Wait for the write to complete, and watch C-g while
8942 at that. */
8943 if (detect_input_pending ())
8944 active = MsgWaitForMultipleObjects (2, wait_hnd, FALSE,
8945 INFINITE, QS_ALLINPUT);
8946 else
8947 active = WaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE);
8948 switch (active)
8950 case WAIT_OBJECT_0:
8951 /* User pressed C-g, cancel write, then leave.
8952 Don't bother cleaning up as we may only get stuck
8953 in buggy drivers. */
8954 PurgeComm (hnd, PURGE_TXABORT | PURGE_TXCLEAR);
8955 CancelIo (hnd);
8956 errno = EIO; /* Why not EINTR? */
8957 nchars = -1;
8958 break;
8959 case WAIT_OBJECT_0 + 1:
8960 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &nchars, TRUE))
8962 errno = EIO;
8963 nchars = -1;
8965 break;
8970 else if (fd < MAXDESC && fd_info[fd].flags & FILE_SOCKET)
8972 unsigned long nblock = 0;
8973 if (winsock_lib == NULL) emacs_abort ();
8975 child_process *cp = fd_info[fd].cp;
8977 /* If this is a non-blocking socket whose connection is in
8978 progress or terminated with an error already, return the
8979 proper error code to the caller. */
8980 if (cp != NULL && (fd_info[fd].flags & FILE_CONNECT) != 0)
8982 /* In case connection is in progress, ENOTCONN that would
8983 result from calling pfn_send is not what callers expect. */
8984 if (cp->status != STATUS_CONNECT_FAILED)
8986 errno = EWOULDBLOCK;
8987 return -1;
8989 /* In case connection failed, use the actual error code
8990 stashed by '_sys_wait_connect' in cp->errcode. */
8991 else if (cp->errcode != 0)
8993 pfn_WSASetLastError (cp->errcode);
8994 set_errno ();
8995 return -1;
8999 /* TODO: implement select() properly so non-blocking I/O works. */
9000 /* For now, make sure the write blocks. */
9001 if (fd_info[fd].flags & FILE_NDELAY)
9002 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
9004 nchars = pfn_send (SOCK_HANDLE (fd), buffer, count, 0);
9006 if (nchars == SOCKET_ERROR)
9008 set_errno ();
9009 DebPrint (("sys_write.send failed with error %d on socket %ld\n",
9010 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
9013 /* Set the socket back to non-blocking if it was before,
9014 for other operations that support it. */
9015 if (fd_info[fd].flags & FILE_NDELAY)
9017 nblock = 1;
9018 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
9021 else
9023 /* Some networked filesystems don't like too large writes, so
9024 break them into smaller chunks. See the Comments section of
9025 the MSDN documentation of WriteFile for details behind the
9026 choice of the value of CHUNK below. See also the thread
9027 http://thread.gmane.org/gmane.comp.version-control.git/145294
9028 in the git mailing list. */
9029 const unsigned char *p = buffer;
9030 const bool is_pipe = (fd < MAXDESC
9031 && ((fd_info[fd].flags & (FILE_PIPE | FILE_NDELAY))
9032 == (FILE_PIPE | FILE_NDELAY)));
9033 /* Some programs, notably Node.js's node.exe, seem to never
9034 completely empty the pipe, so writing more than the size of
9035 the pipe's buffer always returns ENOSPC, and we loop forever
9036 between send_process and here. As a workaround, write no
9037 more than the pipe's buffer can hold. */
9038 DWORD pipe_buffer_size;
9039 if (is_pipe)
9041 if (!GetNamedPipeInfo ((HANDLE)_get_osfhandle (fd),
9042 NULL, &pipe_buffer_size, NULL, NULL))
9044 DebPrint (("GetNamedPipeInfo: error %u\n", GetLastError ()));
9045 pipe_buffer_size = 4096;
9048 const unsigned chunk = is_pipe ? pipe_buffer_size : 30 * 1024 * 1024;
9050 nchars = 0;
9051 errno = 0;
9052 while (count > 0)
9054 unsigned this_chunk = count < chunk ? count : chunk;
9055 int n = _write (fd, p, this_chunk);
9057 if (n > 0)
9058 nchars += n;
9059 if (n < 0)
9061 /* When there's no buffer space in a pipe that is in the
9062 non-blocking mode, _write returns ENOSPC. We return
9063 EAGAIN instead, which should trigger the logic in
9064 send_process that enters waiting loop and calls
9065 wait_reading_process_output to allow process input to
9066 be accepted during the wait. Those calls to
9067 wait_reading_process_output allow sys_select to
9068 notice when process input becomes available, thus
9069 avoiding deadlock whereby each side of the pipe is
9070 blocked on write, waiting for the other party to read
9071 its end of the pipe. */
9072 if (errno == ENOSPC && is_pipe)
9073 errno = EAGAIN;
9074 if (nchars == 0)
9075 nchars = -1;
9076 break;
9078 else if (n < this_chunk)
9079 break;
9080 count -= n;
9081 p += n;
9085 SAFE_FREE ();
9086 return nchars;
9090 /* Emulation of SIOCGIFCONF and getifaddrs, see process.c. */
9092 /* Return information about network interface IFNAME, or about all
9093 interfaces (if IFNAME is nil). */
9094 static Lisp_Object
9095 network_interface_get_info (Lisp_Object ifname)
9097 ULONG ainfo_len = sizeof (IP_ADAPTER_INFO);
9098 IP_ADAPTER_INFO *adapter, *ainfo = xmalloc (ainfo_len);
9099 DWORD retval = get_adapters_info (ainfo, &ainfo_len);
9100 Lisp_Object res = Qnil;
9102 if (retval == ERROR_BUFFER_OVERFLOW)
9104 ainfo = xrealloc (ainfo, ainfo_len);
9105 retval = get_adapters_info (ainfo, &ainfo_len);
9108 if (retval == ERROR_SUCCESS)
9110 int eth_count = 0, tr_count = 0, fddi_count = 0, ppp_count = 0;
9111 int sl_count = 0, wlan_count = 0, lo_count = 0, ifx_count = 0;
9112 int if_num;
9113 struct sockaddr_in sa;
9115 /* For the below, we need some winsock functions, so make sure
9116 the winsock DLL is loaded. If we cannot successfully load
9117 it, they will have no use of the information we provide,
9118 anyway, so punt. */
9119 if (!winsock_lib && !init_winsock (1))
9120 goto done;
9122 for (adapter = ainfo; adapter; adapter = adapter->Next)
9124 char namebuf[MAX_ADAPTER_NAME_LENGTH + 4];
9125 u_long ip_addr;
9126 /* Present Unix-compatible interface names, instead of the
9127 Windows names, which are really GUIDs not readable by
9128 humans. */
9129 static const char *ifmt[] = {
9130 "eth%d", "tr%d", "fddi%d", "ppp%d", "sl%d", "wlan%d",
9131 "lo", "ifx%d"
9133 enum {
9134 NONE = -1,
9135 ETHERNET = 0,
9136 TOKENRING = 1,
9137 FDDI = 2,
9138 PPP = 3,
9139 SLIP = 4,
9140 WLAN = 5,
9141 LOOPBACK = 6,
9142 OTHER_IF = 7
9143 } ifmt_idx;
9145 switch (adapter->Type)
9147 case MIB_IF_TYPE_ETHERNET:
9148 /* Windows before Vista reports wireless adapters as
9149 Ethernet. Work around by looking at the Description
9150 string. */
9151 if (strstr (adapter->Description, "Wireless "))
9153 ifmt_idx = WLAN;
9154 if_num = wlan_count++;
9156 else
9158 ifmt_idx = ETHERNET;
9159 if_num = eth_count++;
9161 break;
9162 case MIB_IF_TYPE_TOKENRING:
9163 ifmt_idx = TOKENRING;
9164 if_num = tr_count++;
9165 break;
9166 case MIB_IF_TYPE_FDDI:
9167 ifmt_idx = FDDI;
9168 if_num = fddi_count++;
9169 break;
9170 case MIB_IF_TYPE_PPP:
9171 ifmt_idx = PPP;
9172 if_num = ppp_count++;
9173 break;
9174 case MIB_IF_TYPE_SLIP:
9175 ifmt_idx = SLIP;
9176 if_num = sl_count++;
9177 break;
9178 case IF_TYPE_IEEE80211:
9179 ifmt_idx = WLAN;
9180 if_num = wlan_count++;
9181 break;
9182 case MIB_IF_TYPE_LOOPBACK:
9183 if (lo_count < 0)
9185 ifmt_idx = LOOPBACK;
9186 if_num = lo_count++;
9188 else
9189 ifmt_idx = NONE;
9190 break;
9191 default:
9192 ifmt_idx = OTHER_IF;
9193 if_num = ifx_count++;
9194 break;
9196 if (ifmt_idx == NONE)
9197 continue;
9198 sprintf (namebuf, ifmt[ifmt_idx], if_num);
9200 sa.sin_family = AF_INET;
9201 ip_addr = sys_inet_addr (adapter->IpAddressList.IpAddress.String);
9202 if (ip_addr == INADDR_NONE)
9204 /* Bogus address, skip this interface. */
9205 continue;
9207 sa.sin_addr.s_addr = ip_addr;
9208 sa.sin_port = 0;
9209 if (NILP (ifname))
9210 res = Fcons (Fcons (build_string (namebuf),
9211 conv_sockaddr_to_lisp ((struct sockaddr*) &sa,
9212 sizeof (struct sockaddr))),
9213 res);
9214 else if (strcmp (namebuf, SSDATA (ifname)) == 0)
9216 Lisp_Object hwaddr = Fmake_vector (make_number (6), Qnil);
9217 register struct Lisp_Vector *p = XVECTOR (hwaddr);
9218 Lisp_Object flags = Qnil;
9219 int n;
9220 u_long net_mask;
9222 /* Flags. We guess most of them by type, since the
9223 Windows flags are different and hard to get by. */
9224 flags = Fcons (intern ("up"), flags);
9225 if (ifmt_idx == ETHERNET || ifmt_idx == WLAN)
9227 flags = Fcons (intern ("broadcast"), flags);
9228 flags = Fcons (intern ("multicast"), flags);
9230 flags = Fcons (intern ("running"), flags);
9231 if (ifmt_idx == PPP)
9233 flags = Fcons (intern ("pointopoint"), flags);
9234 flags = Fcons (intern ("noarp"), flags);
9236 if (adapter->HaveWins)
9237 flags = Fcons (intern ("WINS"), flags);
9238 if (adapter->DhcpEnabled)
9239 flags = Fcons (intern ("dynamic"), flags);
9241 res = Fcons (flags, res);
9243 /* Hardware address and its family. */
9244 for (n = 0; n < adapter->AddressLength; n++)
9245 p->contents[n] = make_number ((int) adapter->Address[n]);
9246 /* Windows does not support AF_LINK or AF_PACKET family
9247 of addresses. Use an arbitrary family number that is
9248 identical to what GNU/Linux returns. */
9249 res = Fcons (Fcons (make_number (1), hwaddr), res);
9251 /* Network mask. */
9252 sa.sin_family = AF_INET;
9253 net_mask = sys_inet_addr (adapter->IpAddressList.IpMask.String);
9254 if (net_mask != INADDR_NONE)
9256 sa.sin_addr.s_addr = net_mask;
9257 sa.sin_port = 0;
9258 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
9259 sizeof (struct sockaddr)),
9260 res);
9262 else
9263 res = Fcons (Qnil, res);
9265 sa.sin_family = AF_INET;
9266 if (ip_addr != INADDR_NONE)
9268 /* Broadcast address is only reported by
9269 GetAdaptersAddresses, which is of limited
9270 availability. Generate it on our own. */
9271 u_long bcast_addr = (ip_addr & net_mask) | ~net_mask;
9273 sa.sin_addr.s_addr = bcast_addr;
9274 sa.sin_port = 0;
9275 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
9276 sizeof (struct sockaddr)),
9277 res);
9279 /* IP address. */
9280 sa.sin_addr.s_addr = ip_addr;
9281 sa.sin_port = 0;
9282 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
9283 sizeof (struct sockaddr)),
9284 res);
9286 else
9287 res = Fcons (Qnil, Fcons (Qnil, res));
9290 /* GetAdaptersInfo is documented to not report loopback
9291 interfaces, so we generate one out of thin air. */
9292 if (!lo_count)
9294 sa.sin_family = AF_INET;
9295 sa.sin_port = 0;
9296 if (NILP (ifname))
9298 sa.sin_addr.s_addr = sys_inet_addr ("127.0.0.1");
9299 res = Fcons (Fcons (build_string ("lo"),
9300 conv_sockaddr_to_lisp ((struct sockaddr*) &sa,
9301 sizeof (struct sockaddr))),
9302 res);
9304 else if (strcmp (SSDATA (ifname), "lo") == 0)
9306 res = Fcons (Fcons (intern ("running"),
9307 Fcons (intern ("loopback"),
9308 Fcons (intern ("up"), Qnil))), Qnil);
9309 /* 772 is what 3 different GNU/Linux systems report for
9310 the loopback interface. */
9311 res = Fcons (Fcons (make_number (772),
9312 Fmake_vector (make_number (6),
9313 make_number (0))),
9314 res);
9315 sa.sin_addr.s_addr = sys_inet_addr ("255.0.0.0");
9316 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
9317 sizeof (struct sockaddr)),
9318 res);
9319 sa.sin_addr.s_addr = sys_inet_addr ("0.0.0.0");
9320 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
9321 sizeof (struct sockaddr)),
9322 res);
9323 sa.sin_addr.s_addr = sys_inet_addr ("127.0.0.1");
9324 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
9325 sizeof (struct sockaddr)),
9326 res);
9332 done:
9333 xfree (ainfo);
9334 return res;
9337 Lisp_Object
9338 network_interface_list (void)
9340 return network_interface_get_info (Qnil);
9343 Lisp_Object
9344 network_interface_info (Lisp_Object ifname)
9346 CHECK_STRING (ifname);
9347 return network_interface_get_info (ifname);
9351 /* Workhorse for w32-read-registry, which see. */
9352 Lisp_Object
9353 w32_read_registry (HKEY rootkey, Lisp_Object lkey, Lisp_Object lname)
9355 HKEY hkey = NULL;
9356 LONG status;
9357 DWORD vsize, vtype;
9358 LPBYTE pvalue;
9359 Lisp_Object val, retval;
9360 const char *key, *value_name;
9361 /* The following sizes are according to size limitations
9362 documented in MSDN. */
9363 wchar_t key_w[255+1];
9364 wchar_t value_w[16*1024+1];
9365 bool use_unicode = is_windows_9x () == 0;
9367 if (use_unicode)
9369 Lisp_Object encoded_key, encoded_vname;
9371 /* Convert input strings to UTF-16. */
9372 encoded_key = code_convert_string_norecord (lkey, Qutf_16le, 1);
9373 memcpy (key_w, SSDATA (encoded_key), SBYTES (encoded_key));
9374 /* wchar_t strings need to be terminated by 2 null bytes. */
9375 key_w [SBYTES (encoded_key)/2] = L'\0';
9376 encoded_vname = code_convert_string_norecord (lname, Qutf_16le, 1);
9377 memcpy (value_w, SSDATA (encoded_vname), SBYTES (encoded_vname));
9378 value_w[SBYTES (encoded_vname)/2] = L'\0';
9380 /* Mirror the slashes, if required. */
9381 for (int i = 0; i < SBYTES (encoded_key)/2; i++)
9383 if (key_w[i] == L'/')
9384 key_w[i] = L'\\';
9386 if ((status = reg_open_key_ex_w (rootkey, key_w, 0,
9387 KEY_READ, &hkey)) == ERROR_NOT_SUPPORTED
9388 || (status = reg_query_value_ex_w (hkey, value_w, NULL, NULL, NULL,
9389 &vsize)) == ERROR_NOT_SUPPORTED
9390 || status != ERROR_SUCCESS)
9392 if (hkey)
9393 RegCloseKey (hkey);
9394 if (status != ERROR_NOT_SUPPORTED)
9395 return Qnil;
9396 use_unicode = 0; /* fall back to non-Unicode calls */
9399 if (!use_unicode)
9401 /* Need to copy LKEY because we are going to modify it. */
9402 Lisp_Object local_lkey = Fcopy_sequence (lkey);
9404 /* Mirror the slashes. Note: this has to be done before
9405 encoding, because after encoding we cannot guarantee that a
9406 slash '/' always stands for itself, it could be part of some
9407 multibyte sequence. */
9408 for (int i = 0; i < SBYTES (local_lkey); i++)
9410 if (SSDATA (local_lkey)[i] == '/')
9411 SSDATA (local_lkey)[i] = '\\';
9414 key = SSDATA (ENCODE_SYSTEM (local_lkey));
9415 value_name = SSDATA (ENCODE_SYSTEM (lname));
9417 if ((status = RegOpenKeyEx (rootkey, key, 0,
9418 KEY_READ, &hkey)) != ERROR_SUCCESS
9419 || (status = RegQueryValueEx (hkey, value_name, NULL,
9420 NULL, NULL, &vsize)) != ERROR_SUCCESS)
9422 if (hkey)
9423 RegCloseKey (hkey);
9424 return Qnil;
9428 pvalue = xzalloc (vsize);
9429 if (use_unicode)
9430 status = reg_query_value_ex_w (hkey, value_w, NULL, &vtype, pvalue, &vsize);
9431 else
9432 status = RegQueryValueEx (hkey, value_name, NULL, &vtype, pvalue, &vsize);
9433 if (status != ERROR_SUCCESS)
9435 xfree (pvalue);
9436 RegCloseKey (hkey);
9437 return Qnil;
9440 switch (vtype)
9442 case REG_NONE:
9443 retval = Qt;
9444 break;
9445 case REG_DWORD:
9446 retval = INTEGER_TO_CONS (*((DWORD *)pvalue));
9447 break;
9448 case REG_QWORD:
9449 retval = INTEGER_TO_CONS (*((long long *)pvalue));
9450 break;
9451 case REG_BINARY:
9453 int i;
9454 unsigned char *dbuf = (unsigned char *)pvalue;
9456 val = make_uninit_vector (vsize);
9457 for (i = 0; i < vsize; i++)
9458 ASET (val, i, make_number (dbuf[i]));
9460 retval = val;
9461 break;
9463 case REG_SZ:
9464 if (use_unicode)
9466 /* pvalue ends with 2 null bytes, but we need only one,
9467 and AUTO_STRING_WITH_LEN will add it. */
9468 if (pvalue[vsize - 1] == '\0')
9469 vsize -= 2;
9470 AUTO_STRING_WITH_LEN (sval, (char *)pvalue, vsize);
9471 retval = from_unicode (sval);
9473 else
9475 /* Don't waste a byte on the terminating null character,
9476 since make_unibyte_string will add one anyway. */
9477 if (pvalue[vsize - 1] == '\0')
9478 vsize--;
9479 retval = DECODE_SYSTEM (make_unibyte_string (pvalue, vsize));
9481 break;
9482 case REG_EXPAND_SZ:
9483 if (use_unicode)
9485 wchar_t expanded_w[32*1024];
9486 DWORD dsize = sizeof (expanded_w) / 2;
9487 DWORD produced = expand_environment_strings_w ((wchar_t *)pvalue,
9488 expanded_w,
9489 dsize);
9490 if (produced > 0 && produced < dsize)
9492 AUTO_STRING_WITH_LEN (sval, (char *)expanded_w,
9493 produced * 2 - 2);
9494 retval = from_unicode (sval);
9496 else
9498 if (pvalue[vsize - 1] == '\0')
9499 vsize -= 2;
9500 AUTO_STRING_WITH_LEN (sval, (char *)pvalue, vsize);
9501 retval = from_unicode (sval);
9504 else
9506 char expanded[32*1024]; /* size limitation according to MSDN */
9507 DWORD produced = ExpandEnvironmentStrings ((char *)pvalue,
9508 expanded,
9509 sizeof (expanded));
9510 if (produced > 0 && produced < sizeof (expanded))
9511 retval = make_unibyte_string (expanded, produced - 1);
9512 else
9514 if (pvalue[vsize - 1] == '\0')
9515 vsize--;
9516 retval = make_unibyte_string (pvalue, vsize);
9519 retval = DECODE_SYSTEM (retval);
9521 break;
9522 case REG_MULTI_SZ:
9523 if (use_unicode)
9525 wchar_t *wp = (wchar_t *)pvalue;
9527 val = Qnil;
9528 do {
9529 size_t wslen = wcslen (wp);
9530 AUTO_STRING_WITH_LEN (sval, (char *)wp, wslen * 2);
9531 val = Fcons (from_unicode (sval), val);
9532 wp += wslen + 1;
9533 } while (*wp);
9535 else
9537 char *p = (char *)pvalue;
9539 val = Qnil;
9540 do {
9541 size_t slen = strlen (p);
9543 val = Fcons (DECODE_SYSTEM (make_unibyte_string (p, slen)), val);
9544 p += slen + 1;
9545 } while (*p);
9548 retval = Fnreverse (val);
9549 break;
9550 default:
9551 error ("unsupported registry data type: %d", (int)vtype);
9554 xfree (pvalue);
9555 RegCloseKey (hkey);
9556 return retval;
9560 /* The Windows CRT functions are "optimized for speed", so they don't
9561 check for timezone and DST changes if they were last called less
9562 than 1 minute ago (see http://support.microsoft.com/kb/821231). So
9563 all Emacs features that repeatedly call time functions (e.g.,
9564 display-time) are in real danger of missing timezone and DST
9565 changes. Calling tzset before each localtime call fixes that. */
9566 struct tm *
9567 sys_localtime (const time_t *t)
9569 tzset ();
9570 return localtime (t);
9575 /* Try loading LIBRARY_ID from the file(s) specified in
9576 Vdynamic_library_alist. If the library is loaded successfully,
9577 return the handle of the DLL, and record the filename in the
9578 property :loaded-from of LIBRARY_ID. If the library could not be
9579 found, or when it was already loaded (because the handle is not
9580 recorded anywhere, and so is lost after use), return NULL.
9582 We could also save the handle in :loaded-from, but currently
9583 there's no use case for it. */
9584 HMODULE
9585 w32_delayed_load (Lisp_Object library_id)
9587 HMODULE dll_handle = NULL;
9589 CHECK_SYMBOL (library_id);
9591 if (CONSP (Vdynamic_library_alist)
9592 && NILP (Fassq (library_id, Vlibrary_cache)))
9594 Lisp_Object found = Qnil;
9595 Lisp_Object dlls = Fassq (library_id, Vdynamic_library_alist);
9597 if (CONSP (dlls))
9598 for (dlls = XCDR (dlls); CONSP (dlls); dlls = XCDR (dlls))
9600 Lisp_Object dll = XCAR (dlls);
9601 char name[MAX_UTF8_PATH];
9602 DWORD res = -1;
9604 CHECK_STRING (dll);
9605 dll = ENCODE_FILE (dll);
9606 if (w32_unicode_filenames)
9608 wchar_t name_w[MAX_PATH];
9610 filename_to_utf16 (SSDATA (dll), name_w);
9611 dll_handle = LoadLibraryW (name_w);
9612 if (dll_handle)
9614 res = GetModuleFileNameW (dll_handle, name_w,
9615 sizeof (name_w));
9616 if (res > 0)
9617 filename_from_utf16 (name_w, name);
9620 else
9622 char name_a[MAX_PATH];
9624 filename_to_ansi (SSDATA (dll), name_a);
9625 dll_handle = LoadLibraryA (name_a);
9626 if (dll_handle)
9628 res = GetModuleFileNameA (dll_handle, name_a,
9629 sizeof (name_a));
9630 if (res > 0)
9631 filename_from_ansi (name_a, name);
9634 if (dll_handle)
9636 ptrdiff_t len = strlen (name);
9637 found = Fcons (dll,
9638 (res > 0)
9639 /* Possibly truncated */
9640 ? make_specified_string (name, -1, len, 1)
9641 : Qnil);
9642 /* This prevents thread start and end notifications
9643 from being sent to the DLL, for every thread we
9644 start. We don't need those notifications because
9645 threads we create never use any of these DLLs, only
9646 the main thread uses them. This is supposed to
9647 speed up thread creation. */
9648 DisableThreadLibraryCalls (dll_handle);
9649 break;
9653 Fput (library_id, QCloaded_from, found);
9656 return dll_handle;
9660 void
9661 check_windows_init_file (void)
9663 /* A common indication that Emacs is not installed properly is when
9664 it cannot find the Windows installation file. If this file does
9665 not exist in the expected place, tell the user. */
9667 if (!noninteractive && !inhibit_window_system
9668 /* Vload_path is not yet initialized when we are loading
9669 loadup.el. */
9670 && NILP (Vpurify_flag))
9672 Lisp_Object init_file;
9673 int fd;
9675 /* Implementation note: this function runs early during Emacs
9676 startup, before startup.el is run. So Vload_path is still in
9677 its initial unibyte form, but it holds UTF-8 encoded file
9678 names, since init_callproc was already called. So we do not
9679 need to ENCODE_FILE here, but we do need to convert the file
9680 names from UTF-8 to ANSI. */
9681 init_file = build_string ("term/w32-win");
9682 fd = openp (Vload_path, init_file, Fget_load_suffixes (), NULL, Qnil, 0);
9683 if (fd < 0)
9685 Lisp_Object load_path_print = Fprin1_to_string (Vload_path, Qnil);
9686 char *init_file_name = SSDATA (init_file);
9687 char *load_path = SSDATA (load_path_print);
9688 char *buffer = alloca (1024
9689 + strlen (init_file_name)
9690 + strlen (load_path));
9691 char *msg = buffer;
9692 int needed;
9694 sprintf (buffer,
9695 "The Emacs Windows initialization file \"%s.el\" "
9696 "could not be found in your Emacs installation. "
9697 "Emacs checked the following directories for this file:\n"
9698 "\n%s\n\n"
9699 "When Emacs cannot find this file, it usually means that it "
9700 "was not installed properly, or its distribution file was "
9701 "not unpacked properly.\nSee the README.W32 file in the "
9702 "top-level Emacs directory for more information.",
9703 init_file_name, load_path);
9704 needed = pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags,
9705 buffer, -1, NULL, 0);
9706 if (needed > 0)
9708 wchar_t *msg_w = alloca ((needed + 1) * sizeof (wchar_t));
9710 pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags, buffer,
9711 -1, msg_w, needed);
9712 needed = pWideCharToMultiByte (CP_ACP, 0, msg_w, -1,
9713 NULL, 0, NULL, NULL);
9714 if (needed > 0)
9716 char *msg_a = alloca (needed + 1);
9718 pWideCharToMultiByte (CP_ACP, 0, msg_w, -1, msg_a, needed,
9719 NULL, NULL);
9720 msg = msg_a;
9723 MessageBox (NULL,
9724 msg,
9725 "Emacs Abort Dialog",
9726 MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
9727 /* Use the low-level system abort. */
9728 abort ();
9730 else
9732 _close (fd);
9737 void
9738 term_ntproc (int ignored)
9740 (void)ignored;
9742 term_timers ();
9744 /* shutdown the socket interface if necessary */
9745 term_winsock ();
9747 term_w32select ();
9750 void
9751 init_ntproc (int dumping)
9753 sigset_t initial_mask = 0;
9755 /* Initialize the socket interface now if available and requested by
9756 the user by defining PRELOAD_WINSOCK; otherwise loading will be
9757 delayed until open-network-stream is called (w32-has-winsock can
9758 also be used to dynamically load or reload winsock).
9760 Conveniently, init_environment is called before us, so
9761 PRELOAD_WINSOCK can be set in the registry. */
9763 /* Always initialize this correctly. */
9764 winsock_lib = NULL;
9766 if (getenv ("PRELOAD_WINSOCK") != NULL)
9767 init_winsock (TRUE);
9769 /* Initial preparation for subprocess support: replace our standard
9770 handles with non-inheritable versions. */
9772 HANDLE parent;
9773 HANDLE stdin_save = INVALID_HANDLE_VALUE;
9774 HANDLE stdout_save = INVALID_HANDLE_VALUE;
9775 HANDLE stderr_save = INVALID_HANDLE_VALUE;
9777 parent = GetCurrentProcess ();
9779 /* ignore errors when duplicating and closing; typically the
9780 handles will be invalid when running as a gui program. */
9781 DuplicateHandle (parent,
9782 GetStdHandle (STD_INPUT_HANDLE),
9783 parent,
9784 &stdin_save,
9786 FALSE,
9787 DUPLICATE_SAME_ACCESS);
9789 DuplicateHandle (parent,
9790 GetStdHandle (STD_OUTPUT_HANDLE),
9791 parent,
9792 &stdout_save,
9794 FALSE,
9795 DUPLICATE_SAME_ACCESS);
9797 DuplicateHandle (parent,
9798 GetStdHandle (STD_ERROR_HANDLE),
9799 parent,
9800 &stderr_save,
9802 FALSE,
9803 DUPLICATE_SAME_ACCESS);
9805 fclose (stdin);
9806 fclose (stdout);
9807 fclose (stderr);
9809 if (stdin_save != INVALID_HANDLE_VALUE)
9810 _open_osfhandle ((intptr_t) stdin_save, O_TEXT);
9811 else
9812 _open ("nul", O_TEXT | O_NOINHERIT | O_RDONLY);
9813 _fdopen (0, "r");
9815 if (stdout_save != INVALID_HANDLE_VALUE)
9816 _open_osfhandle ((intptr_t) stdout_save, O_TEXT);
9817 else
9818 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
9819 _fdopen (1, "w");
9821 if (stderr_save != INVALID_HANDLE_VALUE)
9822 _open_osfhandle ((intptr_t) stderr_save, O_TEXT);
9823 else
9824 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
9825 _fdopen (2, "w");
9828 /* unfortunately, atexit depends on implementation of malloc */
9829 /* atexit (term_ntproc); */
9830 if (!dumping)
9832 /* Make sure we start with all signals unblocked. */
9833 sigprocmask (SIG_SETMASK, &initial_mask, NULL);
9834 signal (SIGABRT, term_ntproc);
9836 init_timers ();
9838 /* determine which drives are fixed, for GetCachedVolumeInformation */
9840 /* GetDriveType must have trailing backslash. */
9841 char drive[] = "A:\\";
9843 /* Loop over all possible drive letters */
9844 while (*drive <= 'Z')
9846 /* Record if this drive letter refers to a fixed drive. */
9847 fixed_drives[DRIVE_INDEX (*drive)] =
9848 (GetDriveType (drive) == DRIVE_FIXED);
9850 (*drive)++;
9853 /* Reset the volume info cache. */
9854 volume_cache = NULL;
9859 shutdown_handler ensures that buffers' autosave files are
9860 up to date when the user logs off, or the system shuts down.
9862 static BOOL WINAPI
9863 shutdown_handler (DWORD type)
9865 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
9866 if (type == CTRL_CLOSE_EVENT /* User closes console window. */
9867 || type == CTRL_LOGOFF_EVENT /* User logs off. */
9868 || type == CTRL_SHUTDOWN_EVENT) /* User shutsdown. */
9870 /* Shut down cleanly, making sure autosave files are up to date. */
9871 shut_down_emacs (0, Qnil);
9874 /* Allow other handlers to handle this signal. */
9875 return FALSE;
9878 /* On Windows 9X, load UNICOWS.DLL and return its handle, or die. On
9879 NT, return a handle to GDI32.DLL. */
9880 HANDLE
9881 maybe_load_unicows_dll (void)
9883 if (os_subtype == OS_9X)
9885 HANDLE ret = LoadLibrary ("Unicows.dll");
9886 if (ret)
9888 /* These two functions are present on Windows 9X as stubs
9889 that always fail. We need the real implementations from
9890 UNICOWS.DLL, so we must call these functions through
9891 pointers, and assign the correct addresses to these
9892 pointers at program startup (see emacs.c, which calls
9893 this function early on). */
9894 pMultiByteToWideChar =
9895 (MultiByteToWideChar_Proc)GetProcAddress (ret, "MultiByteToWideChar");
9896 pWideCharToMultiByte =
9897 (WideCharToMultiByte_Proc)GetProcAddress (ret, "WideCharToMultiByte");
9898 multiByteToWideCharFlags = MB_ERR_INVALID_CHARS;
9899 return ret;
9901 else
9903 int button;
9905 button = MessageBox (NULL,
9906 "Emacs cannot load the UNICOWS.DLL library.\n"
9907 "This library is essential for using Emacs\n"
9908 "on this system. You need to install it.\n\n"
9909 "Emacs will exit when you click OK.",
9910 "Emacs cannot load UNICOWS.DLL",
9911 MB_ICONERROR | MB_TASKMODAL
9912 | MB_SETFOREGROUND | MB_OK);
9913 switch (button)
9915 case IDOK:
9916 default:
9917 exit (1);
9921 else
9923 /* On NT family of Windows, these two functions are always
9924 linked in, so we just assign their addresses to the 2
9925 pointers; no need for the LoadLibrary dance. */
9926 pMultiByteToWideChar = MultiByteToWideChar;
9927 pWideCharToMultiByte = WideCharToMultiByte;
9928 /* On NT 4.0, though, MB_ERR_INVALID_CHARS is not supported. */
9929 if (w32_major_version < 5)
9930 multiByteToWideCharFlags = 0;
9931 else
9932 multiByteToWideCharFlags = MB_ERR_INVALID_CHARS;
9933 return LoadLibrary ("Gdi32.dll");
9938 globals_of_w32 is used to initialize those global variables that
9939 must always be initialized on startup even when the global variable
9940 initialized is non zero (see the function main in emacs.c).
9942 void
9943 globals_of_w32 (void)
9945 HMODULE kernel32 = GetModuleHandle ("kernel32.dll");
9947 get_process_times_fn = (GetProcessTimes_Proc)
9948 GetProcAddress (kernel32, "GetProcessTimes");
9950 DEFSYM (QCloaded_from, ":loaded-from");
9952 g_b_init_is_windows_9x = 0;
9953 g_b_init_open_process_token = 0;
9954 g_b_init_get_token_information = 0;
9955 g_b_init_lookup_account_sid = 0;
9956 g_b_init_get_sid_sub_authority = 0;
9957 g_b_init_get_sid_sub_authority_count = 0;
9958 g_b_init_get_security_info = 0;
9959 g_b_init_get_file_security_w = 0;
9960 g_b_init_get_file_security_a = 0;
9961 g_b_init_get_security_descriptor_owner = 0;
9962 g_b_init_get_security_descriptor_group = 0;
9963 g_b_init_is_valid_sid = 0;
9964 g_b_init_create_toolhelp32_snapshot = 0;
9965 g_b_init_process32_first = 0;
9966 g_b_init_process32_next = 0;
9967 g_b_init_open_thread_token = 0;
9968 g_b_init_impersonate_self = 0;
9969 g_b_init_revert_to_self = 0;
9970 g_b_init_get_process_memory_info = 0;
9971 g_b_init_get_process_working_set_size = 0;
9972 g_b_init_global_memory_status = 0;
9973 g_b_init_global_memory_status_ex = 0;
9974 g_b_init_equal_sid = 0;
9975 g_b_init_copy_sid = 0;
9976 g_b_init_get_length_sid = 0;
9977 g_b_init_get_native_system_info = 0;
9978 g_b_init_get_system_times = 0;
9979 g_b_init_create_symbolic_link_w = 0;
9980 g_b_init_create_symbolic_link_a = 0;
9981 g_b_init_get_security_descriptor_dacl = 0;
9982 g_b_init_convert_sd_to_sddl = 0;
9983 g_b_init_convert_sddl_to_sd = 0;
9984 g_b_init_is_valid_security_descriptor = 0;
9985 g_b_init_set_file_security_w = 0;
9986 g_b_init_set_file_security_a = 0;
9987 g_b_init_set_named_security_info_w = 0;
9988 g_b_init_set_named_security_info_a = 0;
9989 g_b_init_get_adapters_info = 0;
9990 g_b_init_reg_open_key_ex_w = 0;
9991 g_b_init_reg_query_value_ex_w = 0;
9992 g_b_init_expand_environment_strings_w = 0;
9993 g_b_init_compare_string_w = 0;
9994 g_b_init_debug_break_process = 0;
9995 num_of_processors = 0;
9996 /* The following sets a handler for shutdown notifications for
9997 console apps. This actually applies to Emacs in both console and
9998 GUI modes, since we had to fool windows into thinking emacs is a
9999 console application to get console mode to work. */
10000 SetConsoleCtrlHandler (shutdown_handler, TRUE);
10002 /* "None" is the default group name on standalone workstations. */
10003 strcpy (dflt_group_name, "None");
10005 /* Reset, in case it has some value inherited from dump time. */
10006 w32_stat_get_owner_group = 0;
10008 /* If w32_unicode_filenames is non-zero, we will be using Unicode
10009 (a.k.a. "wide") APIs to invoke functions that accept file
10010 names. */
10011 if (is_windows_9x ())
10012 w32_unicode_filenames = 0;
10013 else
10014 w32_unicode_filenames = 1;
10016 #ifdef HAVE_MODULES
10017 dynlib_reset_last_error ();
10018 #endif
10020 w32_crypto_hprov = (HCRYPTPROV)0;
10023 /* For make-serial-process */
10025 serial_open (Lisp_Object port_obj)
10027 char *port = SSDATA (port_obj);
10028 HANDLE hnd;
10029 child_process *cp;
10030 int fd = -1;
10032 hnd = CreateFile (port, GENERIC_READ | GENERIC_WRITE, 0, 0,
10033 OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
10034 if (hnd == INVALID_HANDLE_VALUE)
10035 error ("Could not open %s", port);
10036 fd = (int) _open_osfhandle ((intptr_t) hnd, 0);
10037 if (fd == -1)
10038 error ("Could not open %s", port);
10040 cp = new_child ();
10041 if (!cp)
10042 error ("Could not create child process");
10043 cp->fd = fd;
10044 cp->status = STATUS_READ_ACKNOWLEDGED;
10045 fd_info[ fd ].hnd = hnd;
10046 fd_info[ fd ].flags |=
10047 FILE_READ | FILE_WRITE | FILE_BINARY | FILE_SERIAL;
10048 if (fd_info[ fd ].cp != NULL)
10050 error ("fd_info[fd = %d] is already in use", fd);
10052 fd_info[ fd ].cp = cp;
10053 cp->ovl_read.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
10054 if (cp->ovl_read.hEvent == NULL)
10055 error ("Could not create read event");
10056 cp->ovl_write.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
10057 if (cp->ovl_write.hEvent == NULL)
10058 error ("Could not create write event");
10060 return fd;
10063 /* For serial-process-configure */
10064 void
10065 serial_configure (struct Lisp_Process *p, Lisp_Object contact)
10067 Lisp_Object childp2 = Qnil;
10068 Lisp_Object tem = Qnil;
10069 HANDLE hnd;
10070 DCB dcb;
10071 COMMTIMEOUTS ct;
10072 char summary[4] = "???"; /* This usually becomes "8N1". */
10074 if ((fd_info[ p->outfd ].flags & FILE_SERIAL) == 0)
10075 error ("Not a serial process");
10076 hnd = fd_info[ p->outfd ].hnd;
10078 childp2 = Fcopy_sequence (p->childp);
10080 /* Initialize timeouts for blocking read and blocking write. */
10081 if (!GetCommTimeouts (hnd, &ct))
10082 error ("GetCommTimeouts() failed");
10083 ct.ReadIntervalTimeout = 0;
10084 ct.ReadTotalTimeoutMultiplier = 0;
10085 ct.ReadTotalTimeoutConstant = 0;
10086 ct.WriteTotalTimeoutMultiplier = 0;
10087 ct.WriteTotalTimeoutConstant = 0;
10088 if (!SetCommTimeouts (hnd, &ct))
10089 error ("SetCommTimeouts() failed");
10090 /* Read port attributes and prepare default configuration. */
10091 memset (&dcb, 0, sizeof (dcb));
10092 dcb.DCBlength = sizeof (DCB);
10093 if (!GetCommState (hnd, &dcb))
10094 error ("GetCommState() failed");
10095 dcb.fBinary = TRUE;
10096 dcb.fNull = FALSE;
10097 dcb.fAbortOnError = FALSE;
10098 /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
10099 dcb.ErrorChar = 0;
10100 dcb.EofChar = 0;
10101 dcb.EvtChar = 0;
10103 /* Configure speed. */
10104 if (!NILP (Fplist_member (contact, QCspeed)))
10105 tem = Fplist_get (contact, QCspeed);
10106 else
10107 tem = Fplist_get (p->childp, QCspeed);
10108 CHECK_NUMBER (tem);
10109 dcb.BaudRate = XINT (tem);
10110 childp2 = Fplist_put (childp2, QCspeed, tem);
10112 /* Configure bytesize. */
10113 if (!NILP (Fplist_member (contact, QCbytesize)))
10114 tem = Fplist_get (contact, QCbytesize);
10115 else
10116 tem = Fplist_get (p->childp, QCbytesize);
10117 if (NILP (tem))
10118 tem = make_number (8);
10119 CHECK_NUMBER (tem);
10120 if (XINT (tem) != 7 && XINT (tem) != 8)
10121 error (":bytesize must be nil (8), 7, or 8");
10122 dcb.ByteSize = XINT (tem);
10123 summary[0] = XINT (tem) + '0';
10124 childp2 = Fplist_put (childp2, QCbytesize, tem);
10126 /* Configure parity. */
10127 if (!NILP (Fplist_member (contact, QCparity)))
10128 tem = Fplist_get (contact, QCparity);
10129 else
10130 tem = Fplist_get (p->childp, QCparity);
10131 if (!NILP (tem) && !EQ (tem, Qeven) && !EQ (tem, Qodd))
10132 error (":parity must be nil (no parity), `even', or `odd'");
10133 dcb.fParity = FALSE;
10134 dcb.Parity = NOPARITY;
10135 dcb.fErrorChar = FALSE;
10136 if (NILP (tem))
10138 summary[1] = 'N';
10140 else if (EQ (tem, Qeven))
10142 summary[1] = 'E';
10143 dcb.fParity = TRUE;
10144 dcb.Parity = EVENPARITY;
10145 dcb.fErrorChar = TRUE;
10147 else if (EQ (tem, Qodd))
10149 summary[1] = 'O';
10150 dcb.fParity = TRUE;
10151 dcb.Parity = ODDPARITY;
10152 dcb.fErrorChar = TRUE;
10154 childp2 = Fplist_put (childp2, QCparity, tem);
10156 /* Configure stopbits. */
10157 if (!NILP (Fplist_member (contact, QCstopbits)))
10158 tem = Fplist_get (contact, QCstopbits);
10159 else
10160 tem = Fplist_get (p->childp, QCstopbits);
10161 if (NILP (tem))
10162 tem = make_number (1);
10163 CHECK_NUMBER (tem);
10164 if (XINT (tem) != 1 && XINT (tem) != 2)
10165 error (":stopbits must be nil (1 stopbit), 1, or 2");
10166 summary[2] = XINT (tem) + '0';
10167 if (XINT (tem) == 1)
10168 dcb.StopBits = ONESTOPBIT;
10169 else if (XINT (tem) == 2)
10170 dcb.StopBits = TWOSTOPBITS;
10171 childp2 = Fplist_put (childp2, QCstopbits, tem);
10173 /* Configure flowcontrol. */
10174 if (!NILP (Fplist_member (contact, QCflowcontrol)))
10175 tem = Fplist_get (contact, QCflowcontrol);
10176 else
10177 tem = Fplist_get (p->childp, QCflowcontrol);
10178 if (!NILP (tem) && !EQ (tem, Qhw) && !EQ (tem, Qsw))
10179 error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
10180 dcb.fOutxCtsFlow = FALSE;
10181 dcb.fOutxDsrFlow = FALSE;
10182 dcb.fDtrControl = DTR_CONTROL_DISABLE;
10183 dcb.fDsrSensitivity = FALSE;
10184 dcb.fTXContinueOnXoff = FALSE;
10185 dcb.fOutX = FALSE;
10186 dcb.fInX = FALSE;
10187 dcb.fRtsControl = RTS_CONTROL_DISABLE;
10188 dcb.XonChar = 17; /* Control-Q */
10189 dcb.XoffChar = 19; /* Control-S */
10190 if (NILP (tem))
10192 /* Already configured. */
10194 else if (EQ (tem, Qhw))
10196 dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
10197 dcb.fOutxCtsFlow = TRUE;
10199 else if (EQ (tem, Qsw))
10201 dcb.fOutX = TRUE;
10202 dcb.fInX = TRUE;
10204 childp2 = Fplist_put (childp2, QCflowcontrol, tem);
10206 /* Activate configuration. */
10207 if (!SetCommState (hnd, &dcb))
10208 error ("SetCommState() failed");
10210 childp2 = Fplist_put (childp2, QCsummary, build_string (summary));
10211 pset_childp (p, childp2);
10214 /* For make-pipe-process */
10215 void
10216 register_aux_fd (int infd)
10218 child_process *cp;
10220 cp = new_child ();
10221 if (!cp)
10222 error ("Could not create child process");
10223 cp->fd = infd;
10224 cp->status = STATUS_READ_ACKNOWLEDGED;
10226 if (fd_info[ infd ].cp != NULL)
10228 error ("fd_info[fd = %d] is already in use", infd);
10230 fd_info[ infd ].cp = cp;
10231 fd_info[ infd ].hnd = (HANDLE) _get_osfhandle (infd);
10234 #ifdef HAVE_GNUTLS
10236 ssize_t
10237 emacs_gnutls_pull (gnutls_transport_ptr_t p, void* buf, size_t sz)
10239 int n, err;
10240 struct Lisp_Process *process = (struct Lisp_Process *)p;
10241 int fd = process->infd;
10243 n = sys_read (fd, (char*)buf, sz);
10245 if (n >= 0)
10246 return n;
10248 err = errno;
10250 /* Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
10251 if (err == EWOULDBLOCK)
10252 err = EAGAIN;
10254 emacs_gnutls_transport_set_errno (process->gnutls_state, err);
10256 return -1;
10259 ssize_t
10260 emacs_gnutls_push (gnutls_transport_ptr_t p, const void* buf, size_t sz)
10262 struct Lisp_Process *process = (struct Lisp_Process *)p;
10263 int fd = process->outfd;
10264 ssize_t n = sys_write (fd, buf, sz);
10266 /* 0 or more bytes written means everything went fine. */
10267 if (n >= 0)
10268 return n;
10270 /* Negative bytes written means we got an error in errno.
10271 Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
10272 emacs_gnutls_transport_set_errno (process->gnutls_state,
10273 errno == EWOULDBLOCK ? EAGAIN : errno);
10275 return -1;
10277 #endif /* HAVE_GNUTLS */
10279 /* end of w32.c */