Dirent functions and directory-files are converted and work.
[emacs/old-mirror.git] / src / w32.c
blob16e381564eeddbb6a230615b801ed3a92ebb39e6
1 /* Utility and Unix shadow routines for GNU Emacs on the Microsoft Windows API.
2 Copyright (C) 1994-1995, 2000-2013 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
6 GNU Emacs is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
20 Geoff Voelker (voelker@cs.washington.edu) 7-29-94
23 #include <mingw_time.h>
24 #include <stddef.h> /* for offsetof */
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <float.h> /* for DBL_EPSILON */
28 #include <io.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <ctype.h>
32 #include <signal.h>
33 #include <sys/file.h>
34 #include <time.h> /* must be before nt/inc/sys/time.h, for MinGW64 */
35 #include <sys/time.h>
36 #include <sys/utime.h>
37 #include <math.h>
39 /* must include CRT headers *before* config.h */
41 #include <config.h>
42 #include <mbstring.h> /* for _mbspbrk, _mbslwr, _mbsrchr, ... */
44 #undef access
45 #undef chdir
46 #undef chmod
47 #undef creat
48 #undef ctime
49 #undef fopen
50 #undef link
51 #undef mkdir
52 #undef open
53 #undef rename
54 #undef rmdir
55 #undef unlink
57 #undef close
58 #undef dup
59 #undef dup2
60 #undef pipe
61 #undef read
62 #undef write
64 #undef strerror
66 #undef localtime
68 #include "lisp.h"
69 #include "epaths.h" /* for SHELL */
71 #include <pwd.h>
72 #include <grp.h>
74 /* MinGW64 (_W64) defines these in its _mingw.h. */
75 #if defined(__GNUC__) && !defined(_W64)
76 #define _ANONYMOUS_UNION
77 #define _ANONYMOUS_STRUCT
78 #endif
79 #include <windows.h>
80 /* Some versions of compiler define MEMORYSTATUSEX, some don't, so we
81 use a different name to avoid compilation problems. */
82 typedef struct _MEMORY_STATUS_EX {
83 DWORD dwLength;
84 DWORD dwMemoryLoad;
85 DWORDLONG ullTotalPhys;
86 DWORDLONG ullAvailPhys;
87 DWORDLONG ullTotalPageFile;
88 DWORDLONG ullAvailPageFile;
89 DWORDLONG ullTotalVirtual;
90 DWORDLONG ullAvailVirtual;
91 DWORDLONG ullAvailExtendedVirtual;
92 } MEMORY_STATUS_EX,*LPMEMORY_STATUS_EX;
94 /* These are here so that GDB would know about these data types. This
95 allows to attach GDB to Emacs when a fatal exception is triggered
96 and Windows pops up the "application needs to be closed" dialog.
97 At that point, _gnu_exception_handler, the top-level exception
98 handler installed by the MinGW startup code, is somewhere on the
99 call-stack of the main thread, so going to that call frame and
100 looking at the argument to _gnu_exception_handler, which is a
101 PEXCEPTION_POINTERS pointer, can reveal the exception code
102 (excptr->ExceptionRecord->ExceptionCode) and the address where the
103 exception happened (excptr->ExceptionRecord->ExceptionAddress), as
104 well as some additional information specific to the exception. */
105 PEXCEPTION_POINTERS excptr;
106 PEXCEPTION_RECORD excprec;
107 PCONTEXT ctxrec;
109 #include <lmcons.h>
110 #include <shlobj.h>
112 #include <tlhelp32.h>
113 #include <psapi.h>
114 #ifndef _MSC_VER
115 #include <w32api.h>
116 #endif
117 #if _WIN32_WINNT < 0x0500
118 #if !defined (__MINGW32__) || __W32API_MAJOR_VERSION < 3 || (__W32API_MAJOR_VERSION == 3 && __W32API_MINOR_VERSION < 15)
119 /* This either is not in psapi.h or guarded by higher value of
120 _WIN32_WINNT than what we use. w32api supplied with MinGW 3.15
121 defines it in psapi.h */
122 typedef struct _PROCESS_MEMORY_COUNTERS_EX {
123 DWORD cb;
124 DWORD PageFaultCount;
125 SIZE_T PeakWorkingSetSize;
126 SIZE_T WorkingSetSize;
127 SIZE_T QuotaPeakPagedPoolUsage;
128 SIZE_T QuotaPagedPoolUsage;
129 SIZE_T QuotaPeakNonPagedPoolUsage;
130 SIZE_T QuotaNonPagedPoolUsage;
131 SIZE_T PagefileUsage;
132 SIZE_T PeakPagefileUsage;
133 SIZE_T PrivateUsage;
134 } PROCESS_MEMORY_COUNTERS_EX,*PPROCESS_MEMORY_COUNTERS_EX;
135 #endif
136 #endif
138 #include <winioctl.h>
139 #include <aclapi.h>
140 #include <sddl.h>
142 #include <sys/acl.h>
144 /* This is not in MinGW's sddl.h (but they are in MSVC headers), so we
145 define them by hand if not already defined. */
146 #ifndef SDDL_REVISION_1
147 #define SDDL_REVISION_1 1
148 #endif /* SDDL_REVISION_1 */
150 #if defined(_MSC_VER) || defined(_W64)
151 /* MSVC and MinGW64 don't provide the definition of
152 REPARSE_DATA_BUFFER and the associated macros, except on ntifs.h,
153 which cannot be included because it triggers conflicts with other
154 Windows API headers. So we define it here by hand. */
156 typedef struct _REPARSE_DATA_BUFFER {
157 ULONG ReparseTag;
158 USHORT ReparseDataLength;
159 USHORT Reserved;
160 union {
161 struct {
162 USHORT SubstituteNameOffset;
163 USHORT SubstituteNameLength;
164 USHORT PrintNameOffset;
165 USHORT PrintNameLength;
166 ULONG Flags;
167 WCHAR PathBuffer[1];
168 } SymbolicLinkReparseBuffer;
169 struct {
170 USHORT SubstituteNameOffset;
171 USHORT SubstituteNameLength;
172 USHORT PrintNameOffset;
173 USHORT PrintNameLength;
174 WCHAR PathBuffer[1];
175 } MountPointReparseBuffer;
176 struct {
177 UCHAR DataBuffer[1];
178 } GenericReparseBuffer;
179 } DUMMYUNIONNAME;
180 } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
182 #ifndef FILE_DEVICE_FILE_SYSTEM
183 #define FILE_DEVICE_FILE_SYSTEM 9
184 #endif
185 #ifndef METHOD_BUFFERED
186 #define METHOD_BUFFERED 0
187 #endif
188 #ifndef FILE_ANY_ACCESS
189 #define FILE_ANY_ACCESS 0x00000000
190 #endif
191 #ifndef CTL_CODE
192 #define CTL_CODE(t,f,m,a) (((t)<<16)|((a)<<14)|((f)<<2)|(m))
193 #endif
194 /* MinGW64 defines FSCTL_GET_REPARSE_POINT on winioctl.h. */
195 #ifndef FSCTL_GET_REPARSE_POINT
196 #define FSCTL_GET_REPARSE_POINT \
197 CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS)
198 #endif
199 #endif
201 /* TCP connection support. */
202 #include <sys/socket.h>
203 #undef socket
204 #undef bind
205 #undef connect
206 #undef htons
207 #undef ntohs
208 #undef inet_addr
209 #undef gethostname
210 #undef gethostbyname
211 #undef getservbyname
212 #undef getpeername
213 #undef shutdown
214 #undef setsockopt
215 #undef listen
216 #undef getsockname
217 #undef accept
218 #undef recvfrom
219 #undef sendto
221 #include <iphlpapi.h> /* should be after winsock2.h */
223 #include "w32.h"
224 #include <dirent.h>
225 #include "w32common.h"
226 #include "w32heap.h"
227 #include "w32select.h"
228 #include "systime.h"
229 #include "dispextern.h" /* for xstrcasecmp */
230 #include "coding.h" /* for Vlocale_coding_system */
232 #include "careadlinkat.h"
233 #include "allocator.h"
235 /* For serial_configure and serial_open. */
236 #include "process.h"
238 typedef HRESULT (WINAPI * ShGetFolderPath_fn)
239 (IN HWND, IN int, IN HANDLE, IN DWORD, OUT char *);
241 Lisp_Object QCloaded_from;
243 void globals_of_w32 (void);
244 static DWORD get_rid (PSID);
245 static int is_symlink (const char *);
246 static char * chase_symlinks (const char *);
247 static int enable_privilege (LPCTSTR, BOOL, TOKEN_PRIVILEGES *);
248 static int restore_privilege (TOKEN_PRIVILEGES *);
249 static BOOL WINAPI revert_to_self (void);
251 static int sys_access (const char *, int);
252 extern void *e_malloc (size_t);
253 extern int sys_select (int, SELECT_TYPE *, SELECT_TYPE *, SELECT_TYPE *,
254 struct timespec *, void *);
255 extern int sys_dup (int);
260 /* Initialization states.
262 WARNING: If you add any more such variables for additional APIs,
263 you MUST add initialization for them to globals_of_w32
264 below. This is because these variables might get set
265 to non-NULL values during dumping, but the dumped Emacs
266 cannot reuse those values, because it could be run on a
267 different version of the OS, where API addresses are
268 different. */
269 static BOOL g_b_init_is_windows_9x;
270 static BOOL g_b_init_open_process_token;
271 static BOOL g_b_init_get_token_information;
272 static BOOL g_b_init_lookup_account_sid;
273 static BOOL g_b_init_get_sid_sub_authority;
274 static BOOL g_b_init_get_sid_sub_authority_count;
275 static BOOL g_b_init_get_security_info;
276 static BOOL g_b_init_get_file_security;
277 static BOOL g_b_init_get_security_descriptor_owner;
278 static BOOL g_b_init_get_security_descriptor_group;
279 static BOOL g_b_init_is_valid_sid;
280 static BOOL g_b_init_create_toolhelp32_snapshot;
281 static BOOL g_b_init_process32_first;
282 static BOOL g_b_init_process32_next;
283 static BOOL g_b_init_open_thread_token;
284 static BOOL g_b_init_impersonate_self;
285 static BOOL g_b_init_revert_to_self;
286 static BOOL g_b_init_get_process_memory_info;
287 static BOOL g_b_init_get_process_working_set_size;
288 static BOOL g_b_init_global_memory_status;
289 static BOOL g_b_init_global_memory_status_ex;
290 static BOOL g_b_init_get_length_sid;
291 static BOOL g_b_init_equal_sid;
292 static BOOL g_b_init_copy_sid;
293 static BOOL g_b_init_get_native_system_info;
294 static BOOL g_b_init_get_system_times;
295 static BOOL g_b_init_create_symbolic_link;
296 static BOOL g_b_init_get_security_descriptor_dacl;
297 static BOOL g_b_init_convert_sd_to_sddl;
298 static BOOL g_b_init_convert_sddl_to_sd;
299 static BOOL g_b_init_is_valid_security_descriptor;
300 static BOOL g_b_init_set_file_security;
301 static BOOL g_b_init_get_adapters_info;
304 BEGIN: Wrapper functions around OpenProcessToken
305 and other functions in advapi32.dll that are only
306 supported in Windows NT / 2k / XP
308 /* ** Function pointer typedefs ** */
309 typedef BOOL (WINAPI * OpenProcessToken_Proc) (
310 HANDLE ProcessHandle,
311 DWORD DesiredAccess,
312 PHANDLE TokenHandle);
313 typedef BOOL (WINAPI * GetTokenInformation_Proc) (
314 HANDLE TokenHandle,
315 TOKEN_INFORMATION_CLASS TokenInformationClass,
316 LPVOID TokenInformation,
317 DWORD TokenInformationLength,
318 PDWORD ReturnLength);
319 typedef BOOL (WINAPI * GetProcessTimes_Proc) (
320 HANDLE process_handle,
321 LPFILETIME creation_time,
322 LPFILETIME exit_time,
323 LPFILETIME kernel_time,
324 LPFILETIME user_time);
326 GetProcessTimes_Proc get_process_times_fn = NULL;
328 #ifdef _UNICODE
329 const char * const LookupAccountSid_Name = "LookupAccountSidW";
330 const char * const GetFileSecurity_Name = "GetFileSecurityW";
331 const char * const SetFileSecurity_Name = "SetFileSecurityW";
332 #else
333 const char * const LookupAccountSid_Name = "LookupAccountSidA";
334 const char * const GetFileSecurity_Name = "GetFileSecurityA";
335 const char * const SetFileSecurity_Name = "SetFileSecurityA";
336 #endif
337 typedef BOOL (WINAPI * LookupAccountSid_Proc) (
338 LPCTSTR lpSystemName,
339 PSID Sid,
340 LPTSTR Name,
341 LPDWORD cbName,
342 LPTSTR DomainName,
343 LPDWORD cbDomainName,
344 PSID_NAME_USE peUse);
345 typedef PDWORD (WINAPI * GetSidSubAuthority_Proc) (
346 PSID pSid,
347 DWORD n);
348 typedef PUCHAR (WINAPI * GetSidSubAuthorityCount_Proc) (
349 PSID pSid);
350 typedef DWORD (WINAPI * GetSecurityInfo_Proc) (
351 HANDLE handle,
352 SE_OBJECT_TYPE ObjectType,
353 SECURITY_INFORMATION SecurityInfo,
354 PSID *ppsidOwner,
355 PSID *ppsidGroup,
356 PACL *ppDacl,
357 PACL *ppSacl,
358 PSECURITY_DESCRIPTOR *ppSecurityDescriptor);
359 typedef BOOL (WINAPI * GetFileSecurity_Proc) (
360 LPCTSTR lpFileName,
361 SECURITY_INFORMATION RequestedInformation,
362 PSECURITY_DESCRIPTOR pSecurityDescriptor,
363 DWORD nLength,
364 LPDWORD lpnLengthNeeded);
365 typedef BOOL (WINAPI *SetFileSecurity_Proc) (
366 LPCTSTR lpFileName,
367 SECURITY_INFORMATION SecurityInformation,
368 PSECURITY_DESCRIPTOR pSecurityDescriptor);
369 typedef BOOL (WINAPI * GetSecurityDescriptorOwner_Proc) (
370 PSECURITY_DESCRIPTOR pSecurityDescriptor,
371 PSID *pOwner,
372 LPBOOL lpbOwnerDefaulted);
373 typedef BOOL (WINAPI * GetSecurityDescriptorGroup_Proc) (
374 PSECURITY_DESCRIPTOR pSecurityDescriptor,
375 PSID *pGroup,
376 LPBOOL lpbGroupDefaulted);
377 typedef BOOL (WINAPI *GetSecurityDescriptorDacl_Proc) (
378 PSECURITY_DESCRIPTOR pSecurityDescriptor,
379 LPBOOL lpbDaclPresent,
380 PACL *pDacl,
381 LPBOOL lpbDaclDefaulted);
382 typedef BOOL (WINAPI * IsValidSid_Proc) (
383 PSID sid);
384 typedef HANDLE (WINAPI * CreateToolhelp32Snapshot_Proc) (
385 DWORD dwFlags,
386 DWORD th32ProcessID);
387 typedef BOOL (WINAPI * Process32First_Proc) (
388 HANDLE hSnapshot,
389 LPPROCESSENTRY32 lppe);
390 typedef BOOL (WINAPI * Process32Next_Proc) (
391 HANDLE hSnapshot,
392 LPPROCESSENTRY32 lppe);
393 typedef BOOL (WINAPI * OpenThreadToken_Proc) (
394 HANDLE ThreadHandle,
395 DWORD DesiredAccess,
396 BOOL OpenAsSelf,
397 PHANDLE TokenHandle);
398 typedef BOOL (WINAPI * ImpersonateSelf_Proc) (
399 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel);
400 typedef BOOL (WINAPI * RevertToSelf_Proc) (void);
401 typedef BOOL (WINAPI * GetProcessMemoryInfo_Proc) (
402 HANDLE Process,
403 PPROCESS_MEMORY_COUNTERS ppsmemCounters,
404 DWORD cb);
405 typedef BOOL (WINAPI * GetProcessWorkingSetSize_Proc) (
406 HANDLE hProcess,
407 PSIZE_T lpMinimumWorkingSetSize,
408 PSIZE_T lpMaximumWorkingSetSize);
409 typedef BOOL (WINAPI * GlobalMemoryStatus_Proc) (
410 LPMEMORYSTATUS lpBuffer);
411 typedef BOOL (WINAPI * GlobalMemoryStatusEx_Proc) (
412 LPMEMORY_STATUS_EX lpBuffer);
413 typedef BOOL (WINAPI * CopySid_Proc) (
414 DWORD nDestinationSidLength,
415 PSID pDestinationSid,
416 PSID pSourceSid);
417 typedef BOOL (WINAPI * EqualSid_Proc) (
418 PSID pSid1,
419 PSID pSid2);
420 typedef DWORD (WINAPI * GetLengthSid_Proc) (
421 PSID pSid);
422 typedef void (WINAPI * GetNativeSystemInfo_Proc) (
423 LPSYSTEM_INFO lpSystemInfo);
424 typedef BOOL (WINAPI * GetSystemTimes_Proc) (
425 LPFILETIME lpIdleTime,
426 LPFILETIME lpKernelTime,
427 LPFILETIME lpUserTime);
428 typedef BOOLEAN (WINAPI *CreateSymbolicLink_Proc) (
429 LPTSTR lpSymlinkFileName,
430 LPTSTR lpTargetFileName,
431 DWORD dwFlags);
432 typedef BOOL (WINAPI *ConvertStringSecurityDescriptorToSecurityDescriptor_Proc) (
433 LPCTSTR StringSecurityDescriptor,
434 DWORD StringSDRevision,
435 PSECURITY_DESCRIPTOR *SecurityDescriptor,
436 PULONG SecurityDescriptorSize);
437 typedef BOOL (WINAPI *ConvertSecurityDescriptorToStringSecurityDescriptor_Proc) (
438 PSECURITY_DESCRIPTOR SecurityDescriptor,
439 DWORD RequestedStringSDRevision,
440 SECURITY_INFORMATION SecurityInformation,
441 LPTSTR *StringSecurityDescriptor,
442 PULONG StringSecurityDescriptorLen);
443 typedef BOOL (WINAPI *IsValidSecurityDescriptor_Proc) (PSECURITY_DESCRIPTOR);
444 typedef DWORD (WINAPI *GetAdaptersInfo_Proc) (
445 PIP_ADAPTER_INFO pAdapterInfo,
446 PULONG pOutBufLen);
448 /* ** A utility function ** */
449 static BOOL
450 is_windows_9x (void)
452 static BOOL s_b_ret = 0;
453 OSVERSIONINFO os_ver;
454 if (g_b_init_is_windows_9x == 0)
456 g_b_init_is_windows_9x = 1;
457 ZeroMemory (&os_ver, sizeof (OSVERSIONINFO));
458 os_ver.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
459 if (GetVersionEx (&os_ver))
461 s_b_ret = (os_ver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
464 return s_b_ret;
467 static Lisp_Object ltime (ULONGLONG);
469 /* Get total user and system times for get-internal-run-time.
470 Returns a list of integers if the times are provided by the OS
471 (NT derivatives), otherwise it returns the result of current-time. */
472 Lisp_Object
473 w32_get_internal_run_time (void)
475 if (get_process_times_fn)
477 FILETIME create, exit, kernel, user;
478 HANDLE proc = GetCurrentProcess ();
479 if ((*get_process_times_fn) (proc, &create, &exit, &kernel, &user))
481 LARGE_INTEGER user_int, kernel_int, total;
482 user_int.LowPart = user.dwLowDateTime;
483 user_int.HighPart = user.dwHighDateTime;
484 kernel_int.LowPart = kernel.dwLowDateTime;
485 kernel_int.HighPart = kernel.dwHighDateTime;
486 total.QuadPart = user_int.QuadPart + kernel_int.QuadPart;
487 return ltime (total.QuadPart);
491 return Fcurrent_time ();
494 /* ** The wrapper functions ** */
496 static BOOL WINAPI
497 open_process_token (HANDLE ProcessHandle,
498 DWORD DesiredAccess,
499 PHANDLE TokenHandle)
501 static OpenProcessToken_Proc s_pfn_Open_Process_Token = NULL;
502 HMODULE hm_advapi32 = NULL;
503 if (is_windows_9x () == TRUE)
505 return FALSE;
507 if (g_b_init_open_process_token == 0)
509 g_b_init_open_process_token = 1;
510 hm_advapi32 = LoadLibrary ("Advapi32.dll");
511 s_pfn_Open_Process_Token =
512 (OpenProcessToken_Proc) GetProcAddress (hm_advapi32, "OpenProcessToken");
514 if (s_pfn_Open_Process_Token == NULL)
516 return FALSE;
518 return (
519 s_pfn_Open_Process_Token (
520 ProcessHandle,
521 DesiredAccess,
522 TokenHandle)
526 static BOOL WINAPI
527 get_token_information (HANDLE TokenHandle,
528 TOKEN_INFORMATION_CLASS TokenInformationClass,
529 LPVOID TokenInformation,
530 DWORD TokenInformationLength,
531 PDWORD ReturnLength)
533 static GetTokenInformation_Proc s_pfn_Get_Token_Information = NULL;
534 HMODULE hm_advapi32 = NULL;
535 if (is_windows_9x () == TRUE)
537 return FALSE;
539 if (g_b_init_get_token_information == 0)
541 g_b_init_get_token_information = 1;
542 hm_advapi32 = LoadLibrary ("Advapi32.dll");
543 s_pfn_Get_Token_Information =
544 (GetTokenInformation_Proc) GetProcAddress (hm_advapi32, "GetTokenInformation");
546 if (s_pfn_Get_Token_Information == NULL)
548 return FALSE;
550 return (
551 s_pfn_Get_Token_Information (
552 TokenHandle,
553 TokenInformationClass,
554 TokenInformation,
555 TokenInformationLength,
556 ReturnLength)
560 static BOOL WINAPI
561 lookup_account_sid (LPCTSTR lpSystemName,
562 PSID Sid,
563 LPTSTR Name,
564 LPDWORD cbName,
565 LPTSTR DomainName,
566 LPDWORD cbDomainName,
567 PSID_NAME_USE peUse)
569 static LookupAccountSid_Proc s_pfn_Lookup_Account_Sid = NULL;
570 HMODULE hm_advapi32 = NULL;
571 if (is_windows_9x () == TRUE)
573 return FALSE;
575 if (g_b_init_lookup_account_sid == 0)
577 g_b_init_lookup_account_sid = 1;
578 hm_advapi32 = LoadLibrary ("Advapi32.dll");
579 s_pfn_Lookup_Account_Sid =
580 (LookupAccountSid_Proc) GetProcAddress (hm_advapi32, LookupAccountSid_Name);
582 if (s_pfn_Lookup_Account_Sid == NULL)
584 return FALSE;
586 return (
587 s_pfn_Lookup_Account_Sid (
588 lpSystemName,
589 Sid,
590 Name,
591 cbName,
592 DomainName,
593 cbDomainName,
594 peUse)
598 static PDWORD WINAPI
599 get_sid_sub_authority (PSID pSid, DWORD n)
601 static GetSidSubAuthority_Proc s_pfn_Get_Sid_Sub_Authority = NULL;
602 static DWORD zero = 0U;
603 HMODULE hm_advapi32 = NULL;
604 if (is_windows_9x () == TRUE)
606 return &zero;
608 if (g_b_init_get_sid_sub_authority == 0)
610 g_b_init_get_sid_sub_authority = 1;
611 hm_advapi32 = LoadLibrary ("Advapi32.dll");
612 s_pfn_Get_Sid_Sub_Authority =
613 (GetSidSubAuthority_Proc) GetProcAddress (
614 hm_advapi32, "GetSidSubAuthority");
616 if (s_pfn_Get_Sid_Sub_Authority == NULL)
618 return &zero;
620 return (s_pfn_Get_Sid_Sub_Authority (pSid, n));
623 static PUCHAR WINAPI
624 get_sid_sub_authority_count (PSID pSid)
626 static GetSidSubAuthorityCount_Proc s_pfn_Get_Sid_Sub_Authority_Count = NULL;
627 static UCHAR zero = 0U;
628 HMODULE hm_advapi32 = NULL;
629 if (is_windows_9x () == TRUE)
631 return &zero;
633 if (g_b_init_get_sid_sub_authority_count == 0)
635 g_b_init_get_sid_sub_authority_count = 1;
636 hm_advapi32 = LoadLibrary ("Advapi32.dll");
637 s_pfn_Get_Sid_Sub_Authority_Count =
638 (GetSidSubAuthorityCount_Proc) GetProcAddress (
639 hm_advapi32, "GetSidSubAuthorityCount");
641 if (s_pfn_Get_Sid_Sub_Authority_Count == NULL)
643 return &zero;
645 return (s_pfn_Get_Sid_Sub_Authority_Count (pSid));
648 static DWORD WINAPI
649 get_security_info (HANDLE handle,
650 SE_OBJECT_TYPE ObjectType,
651 SECURITY_INFORMATION SecurityInfo,
652 PSID *ppsidOwner,
653 PSID *ppsidGroup,
654 PACL *ppDacl,
655 PACL *ppSacl,
656 PSECURITY_DESCRIPTOR *ppSecurityDescriptor)
658 static GetSecurityInfo_Proc s_pfn_Get_Security_Info = NULL;
659 HMODULE hm_advapi32 = NULL;
660 if (is_windows_9x () == TRUE)
662 return FALSE;
664 if (g_b_init_get_security_info == 0)
666 g_b_init_get_security_info = 1;
667 hm_advapi32 = LoadLibrary ("Advapi32.dll");
668 s_pfn_Get_Security_Info =
669 (GetSecurityInfo_Proc) GetProcAddress (
670 hm_advapi32, "GetSecurityInfo");
672 if (s_pfn_Get_Security_Info == NULL)
674 return FALSE;
676 return (s_pfn_Get_Security_Info (handle, ObjectType, SecurityInfo,
677 ppsidOwner, ppsidGroup, ppDacl, ppSacl,
678 ppSecurityDescriptor));
681 static BOOL WINAPI
682 get_file_security (LPCTSTR lpFileName,
683 SECURITY_INFORMATION RequestedInformation,
684 PSECURITY_DESCRIPTOR pSecurityDescriptor,
685 DWORD nLength,
686 LPDWORD lpnLengthNeeded)
688 static GetFileSecurity_Proc s_pfn_Get_File_Security = NULL;
689 HMODULE hm_advapi32 = NULL;
690 if (is_windows_9x () == TRUE)
692 errno = ENOTSUP;
693 return FALSE;
695 if (g_b_init_get_file_security == 0)
697 g_b_init_get_file_security = 1;
698 hm_advapi32 = LoadLibrary ("Advapi32.dll");
699 s_pfn_Get_File_Security =
700 (GetFileSecurity_Proc) GetProcAddress (
701 hm_advapi32, GetFileSecurity_Name);
703 if (s_pfn_Get_File_Security == NULL)
705 errno = ENOTSUP;
706 return FALSE;
708 return (s_pfn_Get_File_Security (lpFileName, RequestedInformation,
709 pSecurityDescriptor, nLength,
710 lpnLengthNeeded));
713 static BOOL WINAPI
714 set_file_security (LPCTSTR lpFileName,
715 SECURITY_INFORMATION SecurityInformation,
716 PSECURITY_DESCRIPTOR pSecurityDescriptor)
718 static SetFileSecurity_Proc s_pfn_Set_File_Security = NULL;
719 HMODULE hm_advapi32 = NULL;
720 if (is_windows_9x () == TRUE)
722 errno = ENOTSUP;
723 return FALSE;
725 if (g_b_init_set_file_security == 0)
727 g_b_init_set_file_security = 1;
728 hm_advapi32 = LoadLibrary ("Advapi32.dll");
729 s_pfn_Set_File_Security =
730 (SetFileSecurity_Proc) GetProcAddress (
731 hm_advapi32, SetFileSecurity_Name);
733 if (s_pfn_Set_File_Security == NULL)
735 errno = ENOTSUP;
736 return FALSE;
738 return (s_pfn_Set_File_Security (lpFileName, SecurityInformation,
739 pSecurityDescriptor));
742 static BOOL WINAPI
743 get_security_descriptor_owner (PSECURITY_DESCRIPTOR pSecurityDescriptor,
744 PSID *pOwner,
745 LPBOOL lpbOwnerDefaulted)
747 static GetSecurityDescriptorOwner_Proc s_pfn_Get_Security_Descriptor_Owner = NULL;
748 HMODULE hm_advapi32 = NULL;
749 if (is_windows_9x () == TRUE)
751 errno = ENOTSUP;
752 return FALSE;
754 if (g_b_init_get_security_descriptor_owner == 0)
756 g_b_init_get_security_descriptor_owner = 1;
757 hm_advapi32 = LoadLibrary ("Advapi32.dll");
758 s_pfn_Get_Security_Descriptor_Owner =
759 (GetSecurityDescriptorOwner_Proc) GetProcAddress (
760 hm_advapi32, "GetSecurityDescriptorOwner");
762 if (s_pfn_Get_Security_Descriptor_Owner == NULL)
764 errno = ENOTSUP;
765 return FALSE;
767 return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor, pOwner,
768 lpbOwnerDefaulted));
771 static BOOL WINAPI
772 get_security_descriptor_group (PSECURITY_DESCRIPTOR pSecurityDescriptor,
773 PSID *pGroup,
774 LPBOOL lpbGroupDefaulted)
776 static GetSecurityDescriptorGroup_Proc s_pfn_Get_Security_Descriptor_Group = NULL;
777 HMODULE hm_advapi32 = NULL;
778 if (is_windows_9x () == TRUE)
780 errno = ENOTSUP;
781 return FALSE;
783 if (g_b_init_get_security_descriptor_group == 0)
785 g_b_init_get_security_descriptor_group = 1;
786 hm_advapi32 = LoadLibrary ("Advapi32.dll");
787 s_pfn_Get_Security_Descriptor_Group =
788 (GetSecurityDescriptorGroup_Proc) GetProcAddress (
789 hm_advapi32, "GetSecurityDescriptorGroup");
791 if (s_pfn_Get_Security_Descriptor_Group == NULL)
793 errno = ENOTSUP;
794 return FALSE;
796 return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor, pGroup,
797 lpbGroupDefaulted));
800 static BOOL WINAPI
801 get_security_descriptor_dacl (PSECURITY_DESCRIPTOR pSecurityDescriptor,
802 LPBOOL lpbDaclPresent,
803 PACL *pDacl,
804 LPBOOL lpbDaclDefaulted)
806 static GetSecurityDescriptorDacl_Proc s_pfn_Get_Security_Descriptor_Dacl = NULL;
807 HMODULE hm_advapi32 = NULL;
808 if (is_windows_9x () == TRUE)
810 errno = ENOTSUP;
811 return FALSE;
813 if (g_b_init_get_security_descriptor_dacl == 0)
815 g_b_init_get_security_descriptor_dacl = 1;
816 hm_advapi32 = LoadLibrary ("Advapi32.dll");
817 s_pfn_Get_Security_Descriptor_Dacl =
818 (GetSecurityDescriptorDacl_Proc) GetProcAddress (
819 hm_advapi32, "GetSecurityDescriptorDacl");
821 if (s_pfn_Get_Security_Descriptor_Dacl == NULL)
823 errno = ENOTSUP;
824 return FALSE;
826 return (s_pfn_Get_Security_Descriptor_Dacl (pSecurityDescriptor,
827 lpbDaclPresent, pDacl,
828 lpbDaclDefaulted));
831 static BOOL WINAPI
832 is_valid_sid (PSID sid)
834 static IsValidSid_Proc s_pfn_Is_Valid_Sid = NULL;
835 HMODULE hm_advapi32 = NULL;
836 if (is_windows_9x () == TRUE)
838 return FALSE;
840 if (g_b_init_is_valid_sid == 0)
842 g_b_init_is_valid_sid = 1;
843 hm_advapi32 = LoadLibrary ("Advapi32.dll");
844 s_pfn_Is_Valid_Sid =
845 (IsValidSid_Proc) GetProcAddress (
846 hm_advapi32, "IsValidSid");
848 if (s_pfn_Is_Valid_Sid == NULL)
850 return FALSE;
852 return (s_pfn_Is_Valid_Sid (sid));
855 static BOOL WINAPI
856 equal_sid (PSID sid1, PSID sid2)
858 static EqualSid_Proc s_pfn_Equal_Sid = NULL;
859 HMODULE hm_advapi32 = NULL;
860 if (is_windows_9x () == TRUE)
862 return FALSE;
864 if (g_b_init_equal_sid == 0)
866 g_b_init_equal_sid = 1;
867 hm_advapi32 = LoadLibrary ("Advapi32.dll");
868 s_pfn_Equal_Sid =
869 (EqualSid_Proc) GetProcAddress (
870 hm_advapi32, "EqualSid");
872 if (s_pfn_Equal_Sid == NULL)
874 return FALSE;
876 return (s_pfn_Equal_Sid (sid1, sid2));
879 static DWORD WINAPI
880 get_length_sid (PSID sid)
882 static GetLengthSid_Proc s_pfn_Get_Length_Sid = NULL;
883 HMODULE hm_advapi32 = NULL;
884 if (is_windows_9x () == TRUE)
886 return 0;
888 if (g_b_init_get_length_sid == 0)
890 g_b_init_get_length_sid = 1;
891 hm_advapi32 = LoadLibrary ("Advapi32.dll");
892 s_pfn_Get_Length_Sid =
893 (GetLengthSid_Proc) GetProcAddress (
894 hm_advapi32, "GetLengthSid");
896 if (s_pfn_Get_Length_Sid == NULL)
898 return 0;
900 return (s_pfn_Get_Length_Sid (sid));
903 static BOOL WINAPI
904 copy_sid (DWORD destlen, PSID dest, PSID src)
906 static CopySid_Proc s_pfn_Copy_Sid = NULL;
907 HMODULE hm_advapi32 = NULL;
908 if (is_windows_9x () == TRUE)
910 return FALSE;
912 if (g_b_init_copy_sid == 0)
914 g_b_init_copy_sid = 1;
915 hm_advapi32 = LoadLibrary ("Advapi32.dll");
916 s_pfn_Copy_Sid =
917 (CopySid_Proc) GetProcAddress (
918 hm_advapi32, "CopySid");
920 if (s_pfn_Copy_Sid == NULL)
922 return FALSE;
924 return (s_pfn_Copy_Sid (destlen, dest, src));
928 END: Wrapper functions around OpenProcessToken
929 and other functions in advapi32.dll that are only
930 supported in Windows NT / 2k / XP
933 static void WINAPI
934 get_native_system_info (LPSYSTEM_INFO lpSystemInfo)
936 static GetNativeSystemInfo_Proc s_pfn_Get_Native_System_Info = NULL;
937 if (is_windows_9x () != TRUE)
939 if (g_b_init_get_native_system_info == 0)
941 g_b_init_get_native_system_info = 1;
942 s_pfn_Get_Native_System_Info =
943 (GetNativeSystemInfo_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
944 "GetNativeSystemInfo");
946 if (s_pfn_Get_Native_System_Info != NULL)
947 s_pfn_Get_Native_System_Info (lpSystemInfo);
949 else
950 lpSystemInfo->dwNumberOfProcessors = -1;
953 static BOOL WINAPI
954 get_system_times (LPFILETIME lpIdleTime,
955 LPFILETIME lpKernelTime,
956 LPFILETIME lpUserTime)
958 static GetSystemTimes_Proc s_pfn_Get_System_times = NULL;
959 if (is_windows_9x () == TRUE)
961 return FALSE;
963 if (g_b_init_get_system_times == 0)
965 g_b_init_get_system_times = 1;
966 s_pfn_Get_System_times =
967 (GetSystemTimes_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
968 "GetSystemTimes");
970 if (s_pfn_Get_System_times == NULL)
971 return FALSE;
972 return (s_pfn_Get_System_times (lpIdleTime, lpKernelTime, lpUserTime));
975 static BOOLEAN WINAPI
976 create_symbolic_link (LPTSTR lpSymlinkFilename,
977 LPTSTR lpTargetFileName,
978 DWORD dwFlags)
980 static CreateSymbolicLink_Proc s_pfn_Create_Symbolic_Link = NULL;
981 BOOLEAN retval;
983 if (is_windows_9x () == TRUE)
985 errno = ENOSYS;
986 return 0;
988 if (g_b_init_create_symbolic_link == 0)
990 g_b_init_create_symbolic_link = 1;
991 #ifdef _UNICODE
992 s_pfn_Create_Symbolic_Link =
993 (CreateSymbolicLink_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
994 "CreateSymbolicLinkW");
995 #else
996 s_pfn_Create_Symbolic_Link =
997 (CreateSymbolicLink_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
998 "CreateSymbolicLinkA");
999 #endif
1001 if (s_pfn_Create_Symbolic_Link == NULL)
1003 errno = ENOSYS;
1004 return 0;
1007 retval = s_pfn_Create_Symbolic_Link (lpSymlinkFilename, lpTargetFileName,
1008 dwFlags);
1009 /* If we were denied creation of the symlink, try again after
1010 enabling the SeCreateSymbolicLinkPrivilege for our process. */
1011 if (!retval)
1013 TOKEN_PRIVILEGES priv_current;
1015 if (enable_privilege (SE_CREATE_SYMBOLIC_LINK_NAME, TRUE, &priv_current))
1017 retval = s_pfn_Create_Symbolic_Link (lpSymlinkFilename, lpTargetFileName,
1018 dwFlags);
1019 restore_privilege (&priv_current);
1020 revert_to_self ();
1023 return retval;
1026 static BOOL WINAPI
1027 is_valid_security_descriptor (PSECURITY_DESCRIPTOR pSecurityDescriptor)
1029 static IsValidSecurityDescriptor_Proc s_pfn_Is_Valid_Security_Descriptor_Proc = NULL;
1031 if (is_windows_9x () == TRUE)
1033 errno = ENOTSUP;
1034 return FALSE;
1037 if (g_b_init_is_valid_security_descriptor == 0)
1039 g_b_init_is_valid_security_descriptor = 1;
1040 s_pfn_Is_Valid_Security_Descriptor_Proc =
1041 (IsValidSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1042 "IsValidSecurityDescriptor");
1044 if (s_pfn_Is_Valid_Security_Descriptor_Proc == NULL)
1046 errno = ENOTSUP;
1047 return FALSE;
1050 return s_pfn_Is_Valid_Security_Descriptor_Proc (pSecurityDescriptor);
1053 static BOOL WINAPI
1054 convert_sd_to_sddl (PSECURITY_DESCRIPTOR SecurityDescriptor,
1055 DWORD RequestedStringSDRevision,
1056 SECURITY_INFORMATION SecurityInformation,
1057 LPTSTR *StringSecurityDescriptor,
1058 PULONG StringSecurityDescriptorLen)
1060 static ConvertSecurityDescriptorToStringSecurityDescriptor_Proc s_pfn_Convert_SD_To_SDDL = NULL;
1061 BOOL retval;
1063 if (is_windows_9x () == TRUE)
1065 errno = ENOTSUP;
1066 return FALSE;
1069 if (g_b_init_convert_sd_to_sddl == 0)
1071 g_b_init_convert_sd_to_sddl = 1;
1072 #ifdef _UNICODE
1073 s_pfn_Convert_SD_To_SDDL =
1074 (ConvertSecurityDescriptorToStringSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1075 "ConvertSecurityDescriptorToStringSecurityDescriptorW");
1076 #else
1077 s_pfn_Convert_SD_To_SDDL =
1078 (ConvertSecurityDescriptorToStringSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1079 "ConvertSecurityDescriptorToStringSecurityDescriptorA");
1080 #endif
1082 if (s_pfn_Convert_SD_To_SDDL == NULL)
1084 errno = ENOTSUP;
1085 return FALSE;
1088 retval = s_pfn_Convert_SD_To_SDDL (SecurityDescriptor,
1089 RequestedStringSDRevision,
1090 SecurityInformation,
1091 StringSecurityDescriptor,
1092 StringSecurityDescriptorLen);
1094 return retval;
1097 static BOOL WINAPI
1098 convert_sddl_to_sd (LPCTSTR StringSecurityDescriptor,
1099 DWORD StringSDRevision,
1100 PSECURITY_DESCRIPTOR *SecurityDescriptor,
1101 PULONG SecurityDescriptorSize)
1103 static ConvertStringSecurityDescriptorToSecurityDescriptor_Proc s_pfn_Convert_SDDL_To_SD = NULL;
1104 BOOL retval;
1106 if (is_windows_9x () == TRUE)
1108 errno = ENOTSUP;
1109 return FALSE;
1112 if (g_b_init_convert_sddl_to_sd == 0)
1114 g_b_init_convert_sddl_to_sd = 1;
1115 #ifdef _UNICODE
1116 s_pfn_Convert_SDDL_To_SD =
1117 (ConvertStringSecurityDescriptorToSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1118 "ConvertStringSecurityDescriptorToSecurityDescriptorW");
1119 #else
1120 s_pfn_Convert_SDDL_To_SD =
1121 (ConvertStringSecurityDescriptorToSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1122 "ConvertStringSecurityDescriptorToSecurityDescriptorA");
1123 #endif
1125 if (s_pfn_Convert_SDDL_To_SD == NULL)
1127 errno = ENOTSUP;
1128 return FALSE;
1131 retval = s_pfn_Convert_SDDL_To_SD (StringSecurityDescriptor,
1132 StringSDRevision,
1133 SecurityDescriptor,
1134 SecurityDescriptorSize);
1136 return retval;
1139 static DWORD WINAPI
1140 get_adapters_info (PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen)
1142 static GetAdaptersInfo_Proc s_pfn_Get_Adapters_Info = NULL;
1143 HMODULE hm_iphlpapi = NULL;
1145 if (is_windows_9x () == TRUE)
1146 return ERROR_NOT_SUPPORTED;
1148 if (g_b_init_get_adapters_info == 0)
1150 g_b_init_get_adapters_info = 1;
1151 hm_iphlpapi = LoadLibrary ("Iphlpapi.dll");
1152 if (hm_iphlpapi)
1153 s_pfn_Get_Adapters_Info = (GetAdaptersInfo_Proc)
1154 GetProcAddress (hm_iphlpapi, "GetAdaptersInfo");
1156 if (s_pfn_Get_Adapters_Info == NULL)
1157 return ERROR_NOT_SUPPORTED;
1158 return s_pfn_Get_Adapters_Info (pAdapterInfo, pOutBufLen);
1163 /* Return 1 if P is a valid pointer to an object of size SIZE. Return
1164 0 if P is NOT a valid pointer. Return -1 if we cannot validate P.
1166 This is called from alloc.c:valid_pointer_p. */
1168 w32_valid_pointer_p (void *p, int size)
1170 SIZE_T done;
1171 HANDLE h = OpenProcess (PROCESS_VM_READ, FALSE, GetCurrentProcessId ());
1173 if (h)
1175 unsigned char *buf = alloca (size);
1176 int retval = ReadProcessMemory (h, p, buf, size, &done);
1178 CloseHandle (h);
1179 return retval;
1181 else
1182 return -1;
1187 /* Converting file names from UTF-8 to either UTF-16 or the ANSI
1188 codepage defined by file-name-coding-system. */
1190 /* Current codepage for encoding file names. */
1191 static int file_name_codepage;
1193 /* Produce a Windows ANSI codepage suitable for encoding file names.
1194 Return the information about that codepage in CP_INFO. */
1195 static int
1196 codepage_for_filenames (CPINFO *cp_info)
1198 /* A simple cache to avoid calling GetCPInfo every time we need to
1199 encode/decode a file name. The file-name encoding is not
1200 supposed to be changed too frequently, if ever. */
1201 static Lisp_Object last_file_name_encoding;
1202 static CPINFO cp;
1203 Lisp_Object current_encoding;
1205 current_encoding = Vfile_name_coding_system;
1206 if (NILP (current_encoding))
1207 current_encoding = Vdefault_file_name_coding_system;
1209 if (!EQ (last_file_name_encoding, current_encoding))
1211 /* Default to the current ANSI codepage. */
1212 file_name_codepage = w32_ansi_code_page;
1214 if (NILP (current_encoding))
1216 char *cpname = SDATA (SYMBOL_NAME (current_encoding));
1217 char *cp = NULL, *end;
1218 int cpnum;
1220 if (strncmp (cpname, "cp", 2) == 0)
1221 cp = cpname + 2;
1222 else if (strncmp (cpname, "windows-", 8) == 0)
1223 cp = cpname + 8;
1225 if (cp)
1227 end = cp;
1228 cpnum = strtol (cp, &end, 10);
1229 if (cpnum && *end == '\0' && end - cp >= 2)
1230 file_name_codepage = cpnum;
1234 if (!file_name_codepage)
1235 file_name_codepage = CP_ACP; /* CP_ACP = 0, but let's not assume that */
1237 if (!GetCPInfo (file_name_codepage, &cp))
1239 file_name_codepage = CP_ACP;
1240 if (!GetCPInfo (file_name_codepage, &cp))
1241 emacs_abort ();
1244 if (cp_info)
1245 *cp_info = cp;
1247 return file_name_codepage;
1250 static int
1251 filename_to_utf16 (const char *fn_in, wchar_t *fn_out)
1253 int result = MultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, fn_in, -1,
1254 fn_out, MAX_PATH);
1256 if (!result)
1258 DWORD err = GetLastError ();
1260 switch (err)
1262 case ERROR_INVALID_FLAGS:
1263 case ERROR_INVALID_PARAMETER:
1264 errno = EINVAL;
1265 break;
1266 case ERROR_INSUFFICIENT_BUFFER:
1267 case ERROR_NO_UNICODE_TRANSLATION:
1268 default:
1269 errno = ENOENT;
1270 break;
1272 return -1;
1274 return 0;
1277 static int
1278 filename_from_utf16 (const wchar_t *fn_in, char *fn_out)
1280 int result = WideCharToMultiByte (CP_UTF8, 0, fn_in, -1,
1281 fn_out, MAX_UTF8_PATH, NULL, NULL);
1283 if (!result)
1285 DWORD err = GetLastError ();
1287 switch (err)
1289 case ERROR_INVALID_FLAGS:
1290 case ERROR_INVALID_PARAMETER:
1291 errno = EINVAL;
1292 break;
1293 case ERROR_INSUFFICIENT_BUFFER:
1294 case ERROR_NO_UNICODE_TRANSLATION:
1295 default:
1296 errno = ENOENT;
1297 break;
1299 return -1;
1301 return 0;
1304 static int
1305 filename_to_ansi (const char *fn_in, char *fn_out)
1307 wchar_t fn_utf16[MAX_PATH];
1309 if (filename_to_utf16 (fn_in, fn_utf16) == 0)
1311 int result;
1312 int codepage = codepage_for_filenames (NULL);
1314 result = WideCharToMultiByte (codepage, 0, fn_utf16, -1,
1315 fn_out, MAX_PATH, NULL, NULL);
1316 if (!result)
1318 DWORD err = GetLastError ();
1320 switch (err)
1322 case ERROR_INVALID_FLAGS:
1323 case ERROR_INVALID_PARAMETER:
1324 errno = EINVAL;
1325 break;
1326 case ERROR_INSUFFICIENT_BUFFER:
1327 case ERROR_NO_UNICODE_TRANSLATION:
1328 default:
1329 errno = ENOENT;
1330 break;
1332 return -1;
1334 return 0;
1336 return -1;
1340 filename_from_ansi (const char *fn_in, char *fn_out)
1342 wchar_t fn_utf16[MAX_PATH];
1343 int codepage = codepage_for_filenames (NULL);
1344 int result = MultiByteToWideChar (codepage, MB_ERR_INVALID_CHARS, fn_in, -1,
1345 fn_utf16, MAX_PATH);
1347 if (!result)
1349 DWORD err = GetLastError ();
1351 switch (err)
1353 case ERROR_INVALID_FLAGS:
1354 case ERROR_INVALID_PARAMETER:
1355 errno = EINVAL;
1356 break;
1357 case ERROR_INSUFFICIENT_BUFFER:
1358 case ERROR_NO_UNICODE_TRANSLATION:
1359 default:
1360 errno = ENOENT;
1361 break;
1363 return -1;
1365 return filename_from_utf16 (fn_utf16, fn_out);
1370 /* The directory where we started, in UTF-8. */
1371 static char startup_dir[MAX_UTF8_PATH];
1373 /* Get the current working directory. */
1374 char *
1375 getcwd (char *dir, int dirsize)
1377 if (!dirsize)
1379 errno = EINVAL;
1380 return NULL;
1382 if (dirsize <= strlen (startup_dir))
1384 errno = ERANGE;
1385 return NULL;
1387 #if 0
1388 if (GetCurrentDirectory (MAXPATHLEN, dir) > 0)
1389 return dir;
1390 return NULL;
1391 #else
1392 /* Emacs doesn't actually change directory itself, it stays in the
1393 same directory where it was started. */
1394 strcpy (dir, startup_dir);
1395 return dir;
1396 #endif
1399 /* Emulate getloadavg. */
1401 struct load_sample {
1402 time_t sample_time;
1403 ULONGLONG idle;
1404 ULONGLONG kernel;
1405 ULONGLONG user;
1408 /* Number of processors on this machine. */
1409 static unsigned num_of_processors;
1411 /* We maintain 1-sec samples for the last 16 minutes in a circular buffer. */
1412 static struct load_sample samples[16*60];
1413 static int first_idx = -1, last_idx = -1;
1414 static int max_idx = sizeof (samples) / sizeof (samples[0]);
1416 static int
1417 buf_next (int from)
1419 int next_idx = from + 1;
1421 if (next_idx >= max_idx)
1422 next_idx = 0;
1424 return next_idx;
1427 static int
1428 buf_prev (int from)
1430 int prev_idx = from - 1;
1432 if (prev_idx < 0)
1433 prev_idx = max_idx - 1;
1435 return prev_idx;
1438 static void
1439 sample_system_load (ULONGLONG *idle, ULONGLONG *kernel, ULONGLONG *user)
1441 SYSTEM_INFO sysinfo;
1442 FILETIME ft_idle, ft_user, ft_kernel;
1444 /* Initialize the number of processors on this machine. */
1445 if (num_of_processors <= 0)
1447 get_native_system_info (&sysinfo);
1448 num_of_processors = sysinfo.dwNumberOfProcessors;
1449 if (num_of_processors <= 0)
1451 GetSystemInfo (&sysinfo);
1452 num_of_processors = sysinfo.dwNumberOfProcessors;
1454 if (num_of_processors <= 0)
1455 num_of_processors = 1;
1458 /* TODO: Take into account threads that are ready to run, by
1459 sampling the "\System\Processor Queue Length" performance
1460 counter. The code below accounts only for threads that are
1461 actually running. */
1463 if (get_system_times (&ft_idle, &ft_kernel, &ft_user))
1465 ULARGE_INTEGER uidle, ukernel, uuser;
1467 memcpy (&uidle, &ft_idle, sizeof (ft_idle));
1468 memcpy (&ukernel, &ft_kernel, sizeof (ft_kernel));
1469 memcpy (&uuser, &ft_user, sizeof (ft_user));
1470 *idle = uidle.QuadPart;
1471 *kernel = ukernel.QuadPart;
1472 *user = uuser.QuadPart;
1474 else
1476 *idle = 0;
1477 *kernel = 0;
1478 *user = 0;
1482 /* Produce the load average for a given time interval, using the
1483 samples in the samples[] array. WHICH can be 0, 1, or 2, meaning
1484 1-minute, 5-minute, or 15-minute average, respectively. */
1485 static double
1486 getavg (int which)
1488 double retval = -1.0;
1489 double tdiff;
1490 int idx;
1491 double span = (which == 0 ? 1.0 : (which == 1 ? 5.0 : 15.0)) * 60;
1492 time_t now = samples[last_idx].sample_time;
1494 if (first_idx != last_idx)
1496 for (idx = buf_prev (last_idx); ; idx = buf_prev (idx))
1498 tdiff = difftime (now, samples[idx].sample_time);
1499 if (tdiff >= span - 2*DBL_EPSILON*now)
1501 long double sys =
1502 samples[last_idx].kernel + samples[last_idx].user
1503 - (samples[idx].kernel + samples[idx].user);
1504 long double idl = samples[last_idx].idle - samples[idx].idle;
1506 retval = (1.0 - idl / sys) * num_of_processors;
1507 break;
1509 if (idx == first_idx)
1510 break;
1514 return retval;
1518 getloadavg (double loadavg[], int nelem)
1520 int elem;
1521 ULONGLONG idle, kernel, user;
1522 time_t now = time (NULL);
1524 /* Store another sample. We ignore samples that are less than 1 sec
1525 apart. */
1526 if (difftime (now, samples[last_idx].sample_time) >= 1.0 - 2*DBL_EPSILON*now)
1528 sample_system_load (&idle, &kernel, &user);
1529 last_idx = buf_next (last_idx);
1530 samples[last_idx].sample_time = now;
1531 samples[last_idx].idle = idle;
1532 samples[last_idx].kernel = kernel;
1533 samples[last_idx].user = user;
1534 /* If the buffer has more that 15 min worth of samples, discard
1535 the old ones. */
1536 if (first_idx == -1)
1537 first_idx = last_idx;
1538 while (first_idx != last_idx
1539 && (difftime (now, samples[first_idx].sample_time)
1540 >= 15.0*60 + 2*DBL_EPSILON*now))
1541 first_idx = buf_next (first_idx);
1544 for (elem = 0; elem < nelem; elem++)
1546 double avg = getavg (elem);
1548 if (avg < 0)
1549 break;
1550 loadavg[elem] = avg;
1553 return elem;
1556 /* Emulate getpwuid, getpwnam and others. */
1558 #define PASSWD_FIELD_SIZE 256
1560 static char dflt_passwd_name[PASSWD_FIELD_SIZE];
1561 static char dflt_passwd_passwd[PASSWD_FIELD_SIZE];
1562 static char dflt_passwd_gecos[PASSWD_FIELD_SIZE];
1563 static char dflt_passwd_dir[MAX_UTF8_PATH];
1564 static char dflt_passwd_shell[MAX_UTF8_PATH];
1566 static struct passwd dflt_passwd =
1568 dflt_passwd_name,
1569 dflt_passwd_passwd,
1573 dflt_passwd_gecos,
1574 dflt_passwd_dir,
1575 dflt_passwd_shell,
1578 static char dflt_group_name[GNLEN+1];
1580 static struct group dflt_group =
1582 /* When group information is not available, we return this as the
1583 group for all files. */
1584 dflt_group_name,
1588 unsigned
1589 getuid (void)
1591 return dflt_passwd.pw_uid;
1594 unsigned
1595 geteuid (void)
1597 /* I could imagine arguing for checking to see whether the user is
1598 in the Administrators group and returning a UID of 0 for that
1599 case, but I don't know how wise that would be in the long run. */
1600 return getuid ();
1603 unsigned
1604 getgid (void)
1606 return dflt_passwd.pw_gid;
1609 unsigned
1610 getegid (void)
1612 return getgid ();
1615 struct passwd *
1616 getpwuid (unsigned uid)
1618 if (uid == dflt_passwd.pw_uid)
1619 return &dflt_passwd;
1620 return NULL;
1623 struct group *
1624 getgrgid (gid_t gid)
1626 return &dflt_group;
1629 struct passwd *
1630 getpwnam (char *name)
1632 struct passwd *pw;
1634 pw = getpwuid (getuid ());
1635 if (!pw)
1636 return pw;
1638 if (xstrcasecmp (name, pw->pw_name))
1639 return NULL;
1641 return pw;
1644 static void
1645 init_user_info (void)
1647 /* Find the user's real name by opening the process token and
1648 looking up the name associated with the user-sid in that token.
1650 Use the relative portion of the identifier authority value from
1651 the user-sid as the user id value (same for group id using the
1652 primary group sid from the process token). */
1654 char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
1655 DWORD ulength = sizeof (uname), dlength = sizeof (domain), needed;
1656 DWORD glength = sizeof (gname);
1657 HANDLE token = NULL;
1658 SID_NAME_USE user_type;
1659 unsigned char *buf = NULL;
1660 DWORD blen = 0;
1661 TOKEN_USER user_token;
1662 TOKEN_PRIMARY_GROUP group_token;
1663 BOOL result;
1665 result = open_process_token (GetCurrentProcess (), TOKEN_QUERY, &token);
1666 if (result)
1668 result = get_token_information (token, TokenUser, NULL, 0, &blen);
1669 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
1671 buf = xmalloc (blen);
1672 result = get_token_information (token, TokenUser,
1673 (LPVOID)buf, blen, &needed);
1674 if (result)
1676 memcpy (&user_token, buf, sizeof (user_token));
1677 result = lookup_account_sid (NULL, user_token.User.Sid,
1678 uname, &ulength,
1679 domain, &dlength, &user_type);
1682 else
1683 result = FALSE;
1685 if (result)
1687 strcpy (dflt_passwd.pw_name, uname);
1688 /* Determine a reasonable uid value. */
1689 if (xstrcasecmp ("administrator", uname) == 0)
1691 dflt_passwd.pw_uid = 500; /* well-known Administrator uid */
1692 dflt_passwd.pw_gid = 513; /* well-known None gid */
1694 else
1696 /* Use the last sub-authority value of the RID, the relative
1697 portion of the SID, as user/group ID. */
1698 dflt_passwd.pw_uid = get_rid (user_token.User.Sid);
1700 /* Get group id and name. */
1701 result = get_token_information (token, TokenPrimaryGroup,
1702 (LPVOID)buf, blen, &needed);
1703 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
1705 buf = xrealloc (buf, blen = needed);
1706 result = get_token_information (token, TokenPrimaryGroup,
1707 (LPVOID)buf, blen, &needed);
1709 if (result)
1711 memcpy (&group_token, buf, sizeof (group_token));
1712 dflt_passwd.pw_gid = get_rid (group_token.PrimaryGroup);
1713 dlength = sizeof (domain);
1714 /* If we can get at the real Primary Group name, use that.
1715 Otherwise, the default group name was already set to
1716 "None" in globals_of_w32. */
1717 if (lookup_account_sid (NULL, group_token.PrimaryGroup,
1718 gname, &glength, NULL, &dlength,
1719 &user_type))
1720 strcpy (dflt_group_name, gname);
1722 else
1723 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
1726 /* If security calls are not supported (presumably because we
1727 are running under Windows 9X), fallback to this: */
1728 else if (GetUserName (uname, &ulength))
1730 strcpy (dflt_passwd.pw_name, uname);
1731 if (xstrcasecmp ("administrator", uname) == 0)
1732 dflt_passwd.pw_uid = 0;
1733 else
1734 dflt_passwd.pw_uid = 123;
1735 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
1737 else
1739 strcpy (dflt_passwd.pw_name, "unknown");
1740 dflt_passwd.pw_uid = 123;
1741 dflt_passwd.pw_gid = 123;
1743 dflt_group.gr_gid = dflt_passwd.pw_gid;
1745 /* Set dir and shell from environment variables. */
1746 if (w32_unicode_filenames)
1748 wchar_t *home = _wgetenv (L"HOME");
1749 wchar_t *shell = _wgetenv (L"SHELL");
1751 /* Ensure HOME and SHELL are defined. */
1752 if (home == NULL)
1753 emacs_abort ();
1754 if (shell == NULL)
1755 emacs_abort ();
1756 filename_from_utf16 (home, dflt_passwd.pw_dir);
1757 filename_from_utf16 (shell, dflt_passwd.pw_shell);
1759 else
1761 char *home = getenv ("HOME");
1762 char *shell = getenv ("SHELL");
1764 if (home == NULL)
1765 emacs_abort ();
1766 if (shell == NULL)
1767 emacs_abort ();
1768 filename_from_ansi (home, dflt_passwd.pw_dir);
1769 filename_from_ansi (shell, dflt_passwd.pw_shell);
1772 xfree (buf);
1773 if (token)
1774 CloseHandle (token);
1778 random (void)
1780 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
1781 return ((rand () << 15) | rand ());
1784 void
1785 srandom (int seed)
1787 srand (seed);
1790 /* Return the maximum length in bytes of a multibyte character
1791 sequence encoded in the current ANSI codepage. This is required to
1792 correctly walk the encoded file names one character at a time. */
1793 static int
1794 max_filename_mbslen (void)
1796 CPINFO cp_info;
1798 codepage_for_filenames (&cp_info);
1799 return cp_info.MaxCharSize;
1802 /* Normalize filename by converting in-place all of its path
1803 separators to the separator specified by PATH_SEP. */
1805 static void
1806 normalize_filename (register char *fp, char path_sep)
1808 char *p2;
1810 /* Always lower-case drive letters a-z, even if the filesystem
1811 preserves case in filenames.
1812 This is so filenames can be compared by string comparison
1813 functions that are case-sensitive. Even case-preserving filesystems
1814 do not distinguish case in drive letters. */
1815 p2 = fp + 1;
1817 if (*p2 == ':' && *fp >= 'A' && *fp <= 'Z')
1819 *fp += 'a' - 'A';
1820 fp += 2;
1823 while (*fp)
1825 if (*fp == '/' || *fp == '\\')
1826 *fp = path_sep;
1827 fp++;
1831 /* Destructively turn backslashes into slashes. */
1832 void
1833 dostounix_filename (register char *p)
1835 normalize_filename (p, '/');
1838 /* Destructively turn slashes into backslashes. */
1839 void
1840 unixtodos_filename (register char *p)
1842 normalize_filename (p, '\\');
1845 /* Remove all CR's that are followed by a LF.
1846 (From msdos.c...probably should figure out a way to share it,
1847 although this code isn't going to ever change.) */
1848 static int
1849 crlf_to_lf (register int n, register unsigned char *buf)
1851 unsigned char *np = buf;
1852 unsigned char *startp = buf;
1853 unsigned char *endp = buf + n;
1855 if (n == 0)
1856 return n;
1857 while (buf < endp - 1)
1859 if (*buf == 0x0d)
1861 if (*(++buf) != 0x0a)
1862 *np++ = 0x0d;
1864 else
1865 *np++ = *buf++;
1867 if (buf < endp)
1868 *np++ = *buf++;
1869 return np - startp;
1872 /* Parse the root part of file name, if present. Return length and
1873 optionally store pointer to char after root. */
1874 static int
1875 parse_root (const char * name, const char ** pPath)
1877 const char * start = name;
1879 if (name == NULL)
1880 return 0;
1882 /* find the root name of the volume if given */
1883 if (isalpha (name[0]) && name[1] == ':')
1885 /* skip past drive specifier */
1886 name += 2;
1887 if (IS_DIRECTORY_SEP (name[0]))
1888 name++;
1890 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
1892 int slashes = 2;
1894 name += 2;
1897 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
1898 break;
1899 name++;
1901 while ( *name );
1902 if (IS_DIRECTORY_SEP (name[0]))
1903 name++;
1906 if (pPath)
1907 *pPath = name;
1909 return name - start;
1912 /* Get long base name for name; name is assumed to be absolute. */
1913 static int
1914 get_long_basename (char * name, char * buf, int size)
1916 HANDLE dir_handle;
1917 char fname_utf8[MAX_UTF8_PATH];
1918 int len = 0;
1919 int cstatus;
1921 /* Must be valid filename, no wild cards or other invalid characters. */
1922 if (strpbrk (name, "*?|<>\""))
1923 return 0;
1925 if (w32_unicode_filenames)
1927 wchar_t fname_utf16[MAX_PATH];
1928 WIN32_FIND_DATAW find_data_wide;
1930 filename_to_utf16 (name, fname_utf16);
1931 dir_handle = FindFirstFileW (fname_utf16, &find_data_wide);
1932 if (dir_handle != INVALID_HANDLE_VALUE)
1933 cstatus = filename_from_utf16 (find_data_wide.cFileName, fname_utf8);
1935 else
1937 char fname_ansi[MAX_PATH];
1938 WIN32_FIND_DATAA find_data_ansi;
1940 filename_to_ansi (name, fname_ansi);
1941 dir_handle = FindFirstFileA (fname_ansi, &find_data_ansi);
1942 if (dir_handle != INVALID_HANDLE_VALUE)
1943 cstatus = filename_from_ansi (find_data_ansi.cFileName, fname_utf8);
1946 if (cstatus == 0 && (len = strlen (fname_utf8)) < size)
1947 memcpy (buf, fname_utf8, len + 1);
1948 else
1949 len = 0;
1951 if (dir_handle != INVALID_HANDLE_VALUE)
1952 FindClose (dir_handle);
1954 return len;
1957 /* Get long name for file, if possible (assumed to be absolute). */
1958 BOOL
1959 w32_get_long_filename (char * name, char * buf, int size)
1961 char * o = buf;
1962 char * p;
1963 const char * q;
1964 char full[ MAX_UTF8_PATH ];
1965 int len;
1967 len = strlen (name);
1968 if (len >= MAX_UTF8_PATH)
1969 return FALSE;
1971 /* Use local copy for destructive modification. */
1972 memcpy (full, name, len+1);
1973 unixtodos_filename (full);
1975 /* Copy root part verbatim. */
1976 len = parse_root (full, (const char **)&p);
1977 memcpy (o, full, len);
1978 o += len;
1979 *o = '\0';
1980 size -= len;
1982 while (p != NULL && *p)
1984 q = p;
1985 p = strchr (q, '\\');
1986 if (p) *p = '\0';
1987 len = get_long_basename (full, o, size);
1988 if (len > 0)
1990 o += len;
1991 size -= len;
1992 if (p != NULL)
1994 *p++ = '\\';
1995 if (size < 2)
1996 return FALSE;
1997 *o++ = '\\';
1998 size--;
1999 *o = '\0';
2002 else
2003 return FALSE;
2006 return TRUE;
2009 unsigned int
2010 w32_get_short_filename (char * name, char * buf, int size)
2012 if (w32_unicode_filenames)
2014 wchar_t name_utf16[MAX_PATH], short_name[MAX_PATH];
2015 unsigned int retval;
2017 filename_to_utf16 (name, name_utf16);
2018 retval = GetShortPathNameW (name_utf16, short_name, size);
2019 if (retval && retval < size)
2020 filename_from_utf16 (short_name, buf);
2021 return retval;
2023 else
2025 char name_ansi[MAX_PATH];
2027 filename_to_ansi (name, name_ansi);
2028 return GetShortPathNameA (name_ansi, buf, size);
2032 static int
2033 is_unc_volume (const char *filename)
2035 const char *ptr = filename;
2037 if (!IS_DIRECTORY_SEP (ptr[0]) || !IS_DIRECTORY_SEP (ptr[1]) || !ptr[2])
2038 return 0;
2040 if (strpbrk (ptr + 2, "*?|<>\"\\/"))
2041 return 0;
2043 return 1;
2046 /* Emulate the Posix unsetenv. */
2048 unsetenv (const char *name)
2050 char *var;
2051 size_t name_len;
2052 int retval;
2054 if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
2056 errno = EINVAL;
2057 return -1;
2059 name_len = strlen (name);
2060 /* MS docs says an environment variable cannot be longer than 32K. */
2061 if (name_len > 32767)
2063 errno = ENOMEM;
2064 return 0;
2066 /* It is safe to use 'alloca' with 32K size, since the stack is at
2067 least 2MB, and we set it to 8MB in the link command line. */
2068 var = alloca (name_len + 2);
2069 strncpy (var, name, name_len);
2070 var[name_len++] = '=';
2071 var[name_len] = '\0';
2072 return _putenv (var);
2075 /* MS _putenv doesn't support removing a variable when the argument
2076 does not include the '=' character, so we fix that here. */
2078 sys_putenv (char *str)
2080 const char *const name_end = strchr (str, '=');
2082 if (name_end == NULL)
2084 /* Remove the variable from the environment. */
2085 return unsetenv (str);
2088 return _putenv (str);
2091 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
2093 LPBYTE
2094 w32_get_resource (char *key, LPDWORD lpdwtype)
2096 LPBYTE lpvalue;
2097 HKEY hrootkey = NULL;
2098 DWORD cbData;
2100 /* Check both the current user and the local machine to see if
2101 we have any resources. */
2103 if (RegOpenKeyEx (HKEY_CURRENT_USER, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
2105 lpvalue = NULL;
2107 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
2108 && (lpvalue = xmalloc (cbData)) != NULL
2109 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
2111 RegCloseKey (hrootkey);
2112 return (lpvalue);
2115 xfree (lpvalue);
2117 RegCloseKey (hrootkey);
2120 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
2122 lpvalue = NULL;
2124 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
2125 && (lpvalue = xmalloc (cbData)) != NULL
2126 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
2128 RegCloseKey (hrootkey);
2129 return (lpvalue);
2132 xfree (lpvalue);
2134 RegCloseKey (hrootkey);
2137 return (NULL);
2140 void
2141 init_environment (char ** argv)
2143 static const char * const tempdirs[] = {
2144 "$TMPDIR", "$TEMP", "$TMP", "c:/"
2147 int i;
2149 const int imax = sizeof (tempdirs) / sizeof (tempdirs[0]);
2151 /* Implementation note: This function explicitly works with ANSI
2152 file names, not with UTF-8 encoded file names. This is because
2153 this function pushes variables into the Emacs's environment, and
2154 the environment variables are always assumed to be in the
2155 locale-specific encoding. Do NOT call any functions that accept
2156 UTF-8 file names from this function! */
2158 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
2159 temporary files and assume "/tmp" if $TMPDIR is unset, which
2160 will break on DOS/Windows. Refuse to work if we cannot find
2161 a directory, not even "c:/", usable for that purpose. */
2162 for (i = 0; i < imax ; i++)
2164 const char *tmp = tempdirs[i];
2166 if (*tmp == '$')
2167 tmp = getenv (tmp + 1);
2168 /* Note that `access' can lie to us if the directory resides on a
2169 read-only filesystem, like CD-ROM or a write-protected floppy.
2170 The only way to be really sure is to actually create a file and
2171 see if it succeeds. But I think that's too much to ask. */
2173 /* MSVCRT's _access crashes with D_OK, so we use our replacement. */
2174 if (tmp && sys_access (tmp, D_OK) == 0)
2176 char * var = alloca (strlen (tmp) + 8);
2177 sprintf (var, "TMPDIR=%s", tmp);
2178 _putenv (strdup (var));
2179 break;
2182 if (i >= imax)
2183 cmd_error_internal
2184 (Fcons (Qerror,
2185 Fcons (build_string ("no usable temporary directories found!!"),
2186 Qnil)),
2187 "While setting TMPDIR: ");
2189 /* Check for environment variables and use registry settings if they
2190 don't exist. Fallback on default values where applicable. */
2192 int i;
2193 LPBYTE lpval;
2194 DWORD dwType;
2195 char locale_name[32];
2196 char default_home[MAX_PATH];
2197 int appdata = 0;
2199 static const struct env_entry
2201 char * name;
2202 char * def_value;
2203 } dflt_envvars[] =
2205 /* If the default value is NULL, we will use the value from the
2206 outside environment or the Registry, but will not push the
2207 variable into the Emacs environment if it is defined neither
2208 in the Registry nor in the outside environment. */
2209 {"HOME", "C:/"},
2210 {"PRELOAD_WINSOCK", NULL},
2211 {"emacs_dir", "C:/emacs"},
2212 {"EMACSLOADPATH", NULL},
2213 {"SHELL", "cmdproxy.exe"}, /* perhaps it is somewhere on PATH */
2214 {"EMACSDATA", NULL},
2215 {"EMACSPATH", NULL},
2216 {"INFOPATH", NULL},
2217 {"EMACSDOC", NULL},
2218 {"TERM", "cmd"},
2219 {"LANG", NULL},
2222 #define N_ENV_VARS sizeof (dflt_envvars)/sizeof (dflt_envvars[0])
2224 /* We need to copy dflt_envvars[] and work on the copy because we
2225 don't want the dumped Emacs to inherit the values of
2226 environment variables we saw during dumping (which could be on
2227 a different system). The defaults above must be left intact. */
2228 struct env_entry env_vars[N_ENV_VARS];
2230 for (i = 0; i < N_ENV_VARS; i++)
2231 env_vars[i] = dflt_envvars[i];
2233 /* For backwards compatibility, check if a .emacs file exists in C:/
2234 If not, then we can try to default to the appdata directory under the
2235 user's profile, which is more likely to be writable. */
2236 if (sys_access ("C:/.emacs", F_OK) != 0)
2238 HRESULT profile_result;
2239 /* Dynamically load ShGetFolderPath, as it won't exist on versions
2240 of Windows 95 and NT4 that have not been updated to include
2241 MSIE 5. */
2242 ShGetFolderPath_fn get_folder_path;
2243 get_folder_path = (ShGetFolderPath_fn)
2244 GetProcAddress (GetModuleHandle ("shell32.dll"), "SHGetFolderPathA");
2246 if (get_folder_path != NULL)
2248 profile_result = get_folder_path (NULL, CSIDL_APPDATA, NULL,
2249 0, default_home);
2251 /* If we can't get the appdata dir, revert to old behavior. */
2252 if (profile_result == S_OK)
2254 env_vars[0].def_value = default_home;
2255 appdata = 1;
2260 /* Get default locale info and use it for LANG. */
2261 if (GetLocaleInfo (LOCALE_USER_DEFAULT,
2262 LOCALE_SABBREVLANGNAME | LOCALE_USE_CP_ACP,
2263 locale_name, sizeof (locale_name)))
2265 for (i = 0; i < N_ENV_VARS; i++)
2267 if (strcmp (env_vars[i].name, "LANG") == 0)
2269 env_vars[i].def_value = locale_name;
2270 break;
2275 #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
2277 /* Treat emacs_dir specially: set it unconditionally based on our
2278 location. */
2280 char *p;
2281 char modname[MAX_PATH];
2283 if (!GetModuleFileName (NULL, modname, MAX_PATH))
2284 emacs_abort ();
2285 if ((p = _mbsrchr (modname, '\\')) == NULL)
2286 emacs_abort ();
2287 *p = 0;
2289 if ((p = _mbsrchr (modname, '\\'))
2290 /* From bin means installed Emacs, from src means uninstalled. */
2291 && (xstrcasecmp (p, "\\bin") == 0 || xstrcasecmp (p, "\\src") == 0))
2293 char buf[SET_ENV_BUF_SIZE];
2294 int within_build_tree = xstrcasecmp (p, "\\src") == 0;
2296 *p = 0;
2297 for (p = modname; *p; p = CharNext (p))
2298 if (*p == '\\') *p = '/';
2300 _snprintf (buf, sizeof (buf)-1, "emacs_dir=%s", modname);
2301 _putenv (strdup (buf));
2302 /* If we are running from the Posix-like build tree, define
2303 SHELL to point to our own cmdproxy. The loop below will
2304 then disregard PATH_EXEC and the default value. */
2305 if (within_build_tree)
2307 _snprintf (buf, sizeof (buf) - 1,
2308 "SHELL=%s/nt/cmdproxy.exe", modname);
2309 _putenv (strdup (buf));
2314 for (i = 0; i < N_ENV_VARS; i++)
2316 if (!getenv (env_vars[i].name))
2318 int dont_free = 0;
2319 char bufc[SET_ENV_BUF_SIZE];
2321 if ((lpval = w32_get_resource (env_vars[i].name, &dwType)) == NULL
2322 /* Also ignore empty environment variables. */
2323 || *lpval == 0)
2325 xfree (lpval);
2326 dont_free = 1;
2327 if (strcmp (env_vars[i].name, "SHELL") == 0)
2329 /* Look for cmdproxy.exe in every directory in
2330 PATH_EXEC. FIXME: This does not find cmdproxy
2331 in nt/ when we run uninstalled. */
2332 char fname[MAX_PATH];
2333 const char *pstart = PATH_EXEC, *pend;
2335 do {
2336 pend = _mbschr (pstart, ';');
2337 if (!pend)
2338 pend = pstart + strlen (pstart);
2339 /* Be defensive against series of ;;; characters. */
2340 if (pend > pstart)
2342 strncpy (fname, pstart, pend - pstart);
2343 fname[pend - pstart] = '/';
2344 strcpy (&fname[pend - pstart + 1], "cmdproxy.exe");
2345 ExpandEnvironmentStrings ((LPSTR) fname, bufc,
2346 sizeof (bufc));
2347 if (sys_access (bufc, F_OK) == 0)
2349 lpval = bufc;
2350 dwType = REG_SZ;
2351 break;
2354 if (*pend)
2355 pstart = pend + 1;
2356 else
2357 pstart = pend;
2358 if (!*pstart)
2360 /* If not found in any directory, use the
2361 default as the last resort. */
2362 lpval = env_vars[i].def_value;
2363 dwType = REG_EXPAND_SZ;
2365 } while (*pstart);
2367 else
2369 lpval = env_vars[i].def_value;
2370 dwType = REG_EXPAND_SZ;
2372 if (strcmp (env_vars[i].name, "HOME") == 0 && !appdata)
2373 Vdelayed_warnings_list
2374 = Fcons (listn (CONSTYPE_HEAP, 2,
2375 intern ("initialization"),
2376 build_string ("Setting HOME to C:\\ by default is deprecated")),
2377 Vdelayed_warnings_list);
2380 if (lpval)
2382 char buf1[SET_ENV_BUF_SIZE], buf2[SET_ENV_BUF_SIZE];
2384 if (dwType == REG_EXPAND_SZ)
2385 ExpandEnvironmentStrings ((LPSTR) lpval, buf1, sizeof (buf1));
2386 else if (dwType == REG_SZ)
2387 strcpy (buf1, lpval);
2388 if (dwType == REG_EXPAND_SZ || dwType == REG_SZ)
2390 _snprintf (buf2, sizeof (buf2)-1, "%s=%s", env_vars[i].name,
2391 buf1);
2392 _putenv (strdup (buf2));
2395 if (!dont_free)
2396 xfree (lpval);
2402 /* Rebuild system configuration to reflect invoking system. */
2403 Vsystem_configuration = build_string (EMACS_CONFIGURATION);
2405 /* Another special case: on NT, the PATH variable is actually named
2406 "Path" although cmd.exe (perhaps NT itself) arranges for
2407 environment variable lookup and setting to be case insensitive.
2408 However, Emacs assumes a fully case sensitive environment, so we
2409 need to change "Path" to "PATH" to match the expectations of
2410 various elisp packages. We do this by the sneaky method of
2411 modifying the string in the C runtime environ entry.
2413 The same applies to COMSPEC. */
2415 char ** envp;
2417 for (envp = environ; *envp; envp++)
2418 if (_strnicmp (*envp, "PATH=", 5) == 0)
2419 memcpy (*envp, "PATH=", 5);
2420 else if (_strnicmp (*envp, "COMSPEC=", 8) == 0)
2421 memcpy (*envp, "COMSPEC=", 8);
2424 /* Remember the initial working directory for getcwd. */
2425 /* FIXME: Do we need to resolve possible symlinks in startup_dir?
2426 Does it matter anywhere in Emacs? */
2427 if (w32_unicode_filenames)
2429 wchar_t wstartup_dir[MAX_PATH];
2431 if (!GetCurrentDirectoryW (MAX_PATH, wstartup_dir))
2432 emacs_abort ();
2433 filename_from_utf16 (wstartup_dir, startup_dir);
2435 else
2437 char astartup_dir[MAX_PATH];
2439 if (!GetCurrentDirectoryA (MAX_PATH, astartup_dir))
2440 emacs_abort ();
2441 filename_from_ansi (astartup_dir, startup_dir);
2445 static char modname[MAX_PATH];
2447 if (!GetModuleFileName (NULL, modname, MAX_PATH))
2448 emacs_abort ();
2449 argv[0] = modname;
2452 /* Determine if there is a middle mouse button, to allow parse_button
2453 to decide whether right mouse events should be mouse-2 or
2454 mouse-3. */
2455 w32_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);
2457 init_user_info ();
2460 /* Called from expand-file-name when default-directory is not a string. */
2462 char *
2463 emacs_root_dir (void)
2465 static char root_dir[MAX_UTF8_PATH];
2466 const char *p;
2468 p = getenv ("emacs_dir");
2469 if (p == NULL)
2470 emacs_abort ();
2471 filename_from_ansi (p, root_dir);
2472 root_dir[parse_root (root_dir, NULL)] = '\0';
2473 dostounix_filename (root_dir);
2474 return root_dir;
2477 #include <sys/timeb.h>
2479 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
2481 gettimeofday (struct timeval *__restrict tv, struct timezone *__restrict tz)
2483 struct _timeb tb;
2484 _ftime (&tb);
2486 tv->tv_sec = tb.time;
2487 tv->tv_usec = tb.millitm * 1000L;
2488 /* Implementation note: _ftime sometimes doesn't update the dstflag
2489 according to the new timezone when the system timezone is
2490 changed. We could fix that by using GetSystemTime and
2491 GetTimeZoneInformation, but that doesn't seem necessary, since
2492 Emacs always calls gettimeofday with the 2nd argument NULL (see
2493 current_emacs_time). */
2494 if (tz)
2496 tz->tz_minuteswest = tb.timezone; /* minutes west of Greenwich */
2497 tz->tz_dsttime = tb.dstflag; /* type of dst correction */
2499 return 0;
2502 /* Emulate fdutimens. */
2504 /* Set the access and modification time stamps of FD (a.k.a. FILE) to be
2505 TIMESPEC[0] and TIMESPEC[1], respectively.
2506 FD must be either negative -- in which case it is ignored --
2507 or a file descriptor that is open on FILE.
2508 If FD is nonnegative, then FILE can be NULL, which means
2509 use just futimes instead of utimes.
2510 If TIMESPEC is null, FAIL.
2511 Return 0 on success, -1 (setting errno) on failure. */
2514 fdutimens (int fd, char const *file, struct timespec const timespec[2])
2516 if (!timespec)
2518 errno = ENOSYS;
2519 return -1;
2521 if (fd < 0 && !file)
2523 errno = EBADF;
2524 return -1;
2526 /* _futime's prototype defines 2nd arg as having the type 'struct
2527 _utimbuf', while utime needs to accept 'struct utimbuf' for
2528 compatibility with Posix. So we need to use 2 different (but
2529 equivalent) types to avoid compiler warnings, sigh. */
2530 if (fd >= 0)
2532 struct _utimbuf _ut;
2534 _ut.actime = timespec[0].tv_sec;
2535 _ut.modtime = timespec[1].tv_sec;
2536 return _futime (fd, &_ut);
2538 else
2540 struct utimbuf ut;
2542 ut.actime = timespec[0].tv_sec;
2543 ut.modtime = timespec[1].tv_sec;
2544 /* Call 'utime', which is implemented below, not the MS library
2545 function, which fails on directories. */
2546 return utime (file, &ut);
2551 /* ------------------------------------------------------------------------- */
2552 /* IO support and wrapper functions for the Windows API. */
2553 /* ------------------------------------------------------------------------- */
2555 /* Place a wrapper around the MSVC version of ctime. It returns NULL
2556 on network directories, so we handle that case here.
2557 (Ulrich Leodolter, 1/11/95). */
2558 char *
2559 sys_ctime (const time_t *t)
2561 char *str = (char *) ctime (t);
2562 return (str ? str : "Sun Jan 01 00:00:00 1970");
2565 /* Emulate sleep...we could have done this with a define, but that
2566 would necessitate including windows.h in the files that used it.
2567 This is much easier. */
2568 void
2569 sys_sleep (int seconds)
2571 Sleep (seconds * 1000);
2574 /* Internal MSVC functions for low-level descriptor munging */
2575 extern int __cdecl _set_osfhnd (int fd, long h);
2576 extern int __cdecl _free_osfhnd (int fd);
2578 /* parallel array of private info on file handles */
2579 filedesc fd_info [ MAXDESC ];
2581 typedef struct volume_info_data {
2582 struct volume_info_data * next;
2584 /* time when info was obtained */
2585 DWORD timestamp;
2587 /* actual volume info */
2588 char * root_dir;
2589 DWORD serialnum;
2590 DWORD maxcomp;
2591 DWORD flags;
2592 char * name;
2593 char * type;
2594 } volume_info_data;
2596 /* Global referenced by various functions. */
2597 static volume_info_data volume_info;
2599 /* Vector to indicate which drives are local and fixed (for which cached
2600 data never expires). */
2601 static BOOL fixed_drives[26];
2603 /* Consider cached volume information to be stale if older than 10s,
2604 at least for non-local drives. Info for fixed drives is never stale. */
2605 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
2606 #define VOLINFO_STILL_VALID( root_dir, info ) \
2607 ( ( isalpha (root_dir[0]) && \
2608 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
2609 || GetTickCount () - info->timestamp < 10000 )
2611 /* Cache support functions. */
2613 /* Simple linked list with linear search is sufficient. */
2614 static volume_info_data *volume_cache = NULL;
2616 static volume_info_data *
2617 lookup_volume_info (char * root_dir)
2619 volume_info_data * info;
2621 for (info = volume_cache; info; info = info->next)
2622 if (xstrcasecmp (info->root_dir, root_dir) == 0)
2623 break;
2624 return info;
2627 static void
2628 add_volume_info (char * root_dir, volume_info_data * info)
2630 info->root_dir = xstrdup (root_dir);
2631 unixtodos_filename (info->root_dir);
2632 info->next = volume_cache;
2633 volume_cache = info;
2637 /* Wrapper for GetVolumeInformation, which uses caching to avoid
2638 performance penalty (~2ms on 486 for local drives, 7.5ms for local
2639 cdrom drive, ~5-10ms or more for remote drives on LAN). */
2640 static volume_info_data *
2641 GetCachedVolumeInformation (char * root_dir)
2643 volume_info_data * info;
2644 char default_root[ MAX_UTF8_PATH ];
2645 char name[MAX_PATH+1];
2646 char type[MAX_PATH+1];
2648 /* NULL for root_dir means use root from current directory. */
2649 if (root_dir == NULL)
2651 if (w32_unicode_filenames)
2653 wchar_t curdirw[MAX_PATH];
2655 if (GetCurrentDirectoryW (MAX_PATH, curdirw) == 0)
2656 return NULL;
2657 filename_from_utf16 (curdirw, default_root);
2659 else
2661 char curdira[MAX_PATH];
2663 if (GetCurrentDirectoryA (MAX_PATH, curdira) == 0)
2664 return NULL;
2665 filename_from_ansi (curdira, default_root);
2667 parse_root (default_root, (const char **)&root_dir);
2668 *root_dir = 0;
2669 root_dir = default_root;
2672 /* Local fixed drives can be cached permanently. Removable drives
2673 cannot be cached permanently, since the volume name and serial
2674 number (if nothing else) can change. Remote drives should be
2675 treated as if they are removable, since there is no sure way to
2676 tell whether they are or not. Also, the UNC association of drive
2677 letters mapped to remote volumes can be changed at any time (even
2678 by other processes) without notice.
2680 As a compromise, so we can benefit from caching info for remote
2681 volumes, we use a simple expiry mechanism to invalidate cache
2682 entries that are more than ten seconds old. */
2684 #if 0
2685 /* No point doing this, because WNetGetConnection is even slower than
2686 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
2687 GetDriveType is about the only call of this type which does not
2688 involve network access, and so is extremely quick). */
2690 /* Map drive letter to UNC if remote. */
2691 if (isalpha (root_dir[0]) && !fixed[DRIVE_INDEX (root_dir[0])])
2693 char remote_name[ 256 ];
2694 char drive[3] = { root_dir[0], ':' };
2696 if (WNetGetConnection (drive, remote_name, sizeof (remote_name))
2697 == NO_ERROR)
2698 /* do something */ ;
2700 #endif
2702 info = lookup_volume_info (root_dir);
2704 if (info == NULL || ! VOLINFO_STILL_VALID (root_dir, info))
2706 DWORD serialnum;
2707 DWORD maxcomp;
2708 DWORD flags;
2710 /* Info is not cached, or is stale. */
2711 if (w32_unicode_filenames)
2713 wchar_t root_w[MAX_PATH];
2714 wchar_t name_w[MAX_PATH+1];
2715 wchar_t type_w[MAX_PATH+1];
2717 filename_to_utf16 (root_dir, root_w);
2718 if (!GetVolumeInformationW (root_w,
2719 name_w, sizeof (name_w),
2720 &serialnum,
2721 &maxcomp,
2722 &flags,
2723 type_w, sizeof (type_w)))
2724 return NULL;
2725 /* Hmm... not really 100% correct, as these 2 are not file
2726 names... */
2727 filename_from_utf16 (name_w, name);
2728 filename_from_utf16 (type_w, type);
2730 else
2732 char root_a[MAX_PATH];
2733 char name_a[MAX_PATH+1];
2734 char type_a[MAX_PATH+1];
2736 filename_to_ansi (root_dir, root_a);
2737 if (!GetVolumeInformationA (root_a,
2738 name_a, sizeof (name_a),
2739 &serialnum,
2740 &maxcomp,
2741 &flags,
2742 type_a, sizeof (type_a)))
2743 return NULL;
2744 filename_from_ansi (name_a, name);
2745 filename_from_ansi (type_a, type);
2748 /* Cache the volume information for future use, overwriting existing
2749 entry if present. */
2750 if (info == NULL)
2752 info = xmalloc (sizeof (volume_info_data));
2753 add_volume_info (root_dir, info);
2755 else
2757 xfree (info->name);
2758 xfree (info->type);
2761 info->name = xstrdup (name);
2762 unixtodos_filename (info->name);
2763 info->serialnum = serialnum;
2764 info->maxcomp = maxcomp;
2765 info->flags = flags;
2766 info->type = xstrdup (type);
2767 info->timestamp = GetTickCount ();
2770 return info;
2773 /* Get information on the volume where NAME is held; set path pointer to
2774 start of pathname in NAME (past UNC header\volume header if present),
2775 if pPath is non-NULL.
2777 Note: if NAME includes symlinks, the information is for the volume
2778 of the symlink, not of its target. That's because, even though
2779 GetVolumeInformation returns information about the symlink target
2780 of its argument, we only pass the root directory to
2781 GetVolumeInformation, not the full NAME. */
2782 static int
2783 get_volume_info (const char * name, const char ** pPath)
2785 char temp[MAX_UTF8_PATH];
2786 char *rootname = NULL; /* default to current volume */
2787 volume_info_data * info;
2788 int root_len = parse_root (name, pPath);
2790 if (name == NULL)
2791 return FALSE;
2793 /* Copy the root name of the volume, if given. */
2794 if (root_len)
2796 strncpy (temp, name, root_len);
2797 temp[root_len] = '\0';
2798 unixtodos_filename (temp);
2799 rootname = temp;
2802 info = GetCachedVolumeInformation (rootname);
2803 if (info != NULL)
2805 /* Set global referenced by other functions. */
2806 volume_info = *info;
2807 return TRUE;
2809 return FALSE;
2812 /* Determine if volume is FAT format (ie. only supports short 8.3
2813 names); also set path pointer to start of pathname in name, if
2814 pPath is non-NULL. */
2815 static int
2816 is_fat_volume (const char * name, const char ** pPath)
2818 if (get_volume_info (name, pPath))
2819 return (volume_info.maxcomp == 12);
2820 return FALSE;
2823 /* Convert all slashes in a filename to backslashes, and map filename
2824 to a valid 8.3 name if necessary. The result is a pointer to a
2825 static buffer, so CAVEAT EMPTOR! */
2826 const char *
2827 map_w32_filename (const char * name, const char ** pPath)
2829 static char shortname[MAX_UTF8_PATH];
2830 char * str = shortname;
2831 char c;
2832 char * path;
2833 const char * save_name = name;
2835 if (strlen (name) >= sizeof (shortname))
2837 /* Return a filename which will cause callers to fail. */
2838 strcpy (shortname, "?");
2839 return shortname;
2842 if (is_fat_volume (name, (const char **)&path)) /* truncate to 8.3 */
2844 register int left = 8; /* maximum number of chars in part */
2845 register int extn = 0; /* extension added? */
2846 register int dots = 2; /* maximum number of dots allowed */
2848 while (name < path)
2849 *str++ = *name++; /* skip past UNC header */
2851 while ((c = *name++))
2853 switch ( c )
2855 case ':':
2856 case '\\':
2857 case '/':
2858 *str++ = (c == ':' ? ':' : '\\');
2859 extn = 0; /* reset extension flags */
2860 dots = 2; /* max 2 dots */
2861 left = 8; /* max length 8 for main part */
2862 break;
2863 case '.':
2864 if ( dots )
2866 /* Convert path components of the form .xxx to _xxx,
2867 but leave . and .. as they are. This allows .emacs
2868 to be read as _emacs, for example. */
2870 if (! *name ||
2871 *name == '.' ||
2872 IS_DIRECTORY_SEP (*name))
2874 *str++ = '.';
2875 dots--;
2877 else
2879 *str++ = '_';
2880 left--;
2881 dots = 0;
2884 else if ( !extn )
2886 *str++ = '.';
2887 extn = 1; /* we've got an extension */
2888 left = 3; /* 3 chars in extension */
2890 else
2892 /* any embedded dots after the first are converted to _ */
2893 *str++ = '_';
2895 break;
2896 case '~':
2897 case '#': /* don't lose these, they're important */
2898 if ( ! left )
2899 str[-1] = c; /* replace last character of part */
2900 /* FALLTHRU */
2901 default:
2902 if ( left && 'A' <= c && c <= 'Z' )
2904 *str++ = tolower (c); /* map to lower case (looks nicer) */
2905 left--;
2906 dots = 0; /* started a path component */
2908 break;
2911 *str = '\0';
2913 else
2915 strcpy (shortname, name);
2916 unixtodos_filename (shortname);
2919 if (pPath)
2920 *pPath = shortname + (path - save_name);
2922 return shortname;
2925 static int
2926 is_exec (const char * name)
2928 char * p = strrchr (name, '.');
2929 return
2930 (p != NULL
2931 && (xstrcasecmp (p, ".exe") == 0 ||
2932 xstrcasecmp (p, ".com") == 0 ||
2933 xstrcasecmp (p, ".bat") == 0 ||
2934 xstrcasecmp (p, ".cmd") == 0));
2937 /* Emulate the Unix directory procedures opendir, closedir, and
2938 readdir. We rename them to sys_* names because some versions of
2939 MinGW startup code call opendir and readdir to glob wildcards, and
2940 the code that calls them doesn't grok UTF-8 encoded file names we
2941 produce in dirent->d_name[]. */
2943 struct dirent dir_static; /* simulated directory contents */
2944 static HANDLE dir_find_handle = INVALID_HANDLE_VALUE;
2945 static int dir_is_fat;
2946 static char dir_pathname[MAX_UTF8_PATH];
2947 static WIN32_FIND_DATAW dir_find_data_w;
2948 static WIN32_FIND_DATAA dir_find_data_a;
2950 /* Support shares on a network resource as subdirectories of a read-only
2951 root directory. */
2952 static HANDLE wnet_enum_handle = INVALID_HANDLE_VALUE;
2953 static HANDLE open_unc_volume (const char *);
2954 static void *read_unc_volume (HANDLE, wchar_t *, char *, int);
2955 static void close_unc_volume (HANDLE);
2957 DIR *
2958 sys_opendir (const char *filename)
2960 DIR *dirp;
2962 /* Opening is done by FindFirstFile. However, a read is inherent to
2963 this operation, so we defer the open until read time. */
2965 if (dir_find_handle != INVALID_HANDLE_VALUE)
2966 return NULL;
2967 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
2968 return NULL;
2970 /* Note: We don't support traversal of UNC volumes via symlinks.
2971 Doing so would mean punishing 99.99% of use cases by resolving
2972 all the possible symlinks in FILENAME, recursively. */
2973 if (is_unc_volume (filename))
2975 wnet_enum_handle = open_unc_volume (filename);
2976 if (wnet_enum_handle == INVALID_HANDLE_VALUE)
2977 return NULL;
2980 if (!(dirp = (DIR *) malloc (sizeof (DIR))))
2981 return NULL;
2983 dirp->dd_fd = 0;
2984 dirp->dd_loc = 0;
2985 dirp->dd_size = 0;
2987 strncpy (dir_pathname, map_w32_filename (filename, NULL), MAX_UTF8_PATH - 1);
2988 dir_pathname[MAX_UTF8_PATH - 1] = '\0';
2989 /* Note: We don't support symlinks to file names on FAT volumes.
2990 Doing so would mean punishing 99.99% of use cases by resolving
2991 all the possible symlinks in FILENAME, recursively. */
2992 dir_is_fat = is_fat_volume (filename, NULL);
2994 return dirp;
2997 void
2998 sys_closedir (DIR *dirp)
3000 /* If we have a find-handle open, close it. */
3001 if (dir_find_handle != INVALID_HANDLE_VALUE)
3003 FindClose (dir_find_handle);
3004 dir_find_handle = INVALID_HANDLE_VALUE;
3006 else if (wnet_enum_handle != INVALID_HANDLE_VALUE)
3008 close_unc_volume (wnet_enum_handle);
3009 wnet_enum_handle = INVALID_HANDLE_VALUE;
3011 xfree ((char *) dirp);
3014 struct dirent *
3015 sys_readdir (DIR *dirp)
3017 int downcase = !NILP (Vw32_downcase_file_names);
3019 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
3021 if (!read_unc_volume (wnet_enum_handle,
3022 dir_find_data_w.cFileName,
3023 dir_find_data_a.cFileName,
3024 MAX_PATH))
3025 return NULL;
3027 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
3028 else if (dir_find_handle == INVALID_HANDLE_VALUE)
3030 char filename[MAX_UTF8_PATH + 2];
3031 int ln;
3033 strcpy (filename, dir_pathname);
3034 ln = strlen (filename) - 1;
3035 if (!IS_DIRECTORY_SEP (filename[ln]))
3036 strcat (filename, "\\");
3037 strcat (filename, "*");
3039 /* Note: No need to resolve symlinks in FILENAME, because
3040 FindFirst opens the directory that is the target of a
3041 symlink. */
3042 if (w32_unicode_filenames)
3044 wchar_t fnw[MAX_PATH];
3046 filename_to_utf16 (filename, fnw);
3047 dir_find_handle = FindFirstFileW (fnw, &dir_find_data_w);
3049 else
3051 char fna[MAX_PATH];
3053 filename_to_ansi (filename, fna);
3054 dir_find_handle = FindFirstFileA (fna, &dir_find_data_a);
3057 if (dir_find_handle == INVALID_HANDLE_VALUE)
3058 return NULL;
3060 else if (w32_unicode_filenames)
3062 if (!FindNextFileW (dir_find_handle, &dir_find_data_w))
3063 return NULL;
3065 else
3067 if (!FindNextFileA (dir_find_handle, &dir_find_data_a))
3068 return NULL;
3071 /* Emacs never uses this value, so don't bother making it match
3072 value returned by stat(). */
3073 dir_static.d_ino = 1;
3075 if (w32_unicode_filenames)
3077 if (downcase || dir_is_fat)
3079 wchar_t tem[MAX_PATH];
3081 wcscpy (tem, dir_find_data_w.cFileName);
3082 CharLowerW (tem);
3083 filename_from_utf16 (tem, dir_static.d_name);
3085 else
3086 filename_from_utf16 (dir_find_data_w.cFileName, dir_static.d_name);
3088 else
3090 char tem[MAX_PATH];
3092 /* If the file name in cFileName[] includes `?' characters, it
3093 means the original file name used characters that cannot be
3094 represented by the current ANSI codepage. To avoid total
3095 lossage, retrieve the short 8+3 alias of the long file
3096 name. */
3097 if (_mbspbrk (dir_find_data_a.cFileName, "?"))
3099 strcpy (tem, dir_find_data_a.cAlternateFileName);
3100 /* 8+3 aliases are returned in all caps, which could break
3101 various alists that look at filenames' extensions. */
3102 downcase = 1;
3104 else if (downcase || dir_is_fat)
3105 strcpy (tem, dir_find_data_a.cFileName);
3106 else
3107 filename_from_ansi (dir_find_data_a.cFileName, dir_static.d_name);
3108 if (downcase || dir_is_fat)
3110 _mbslwr (tem);
3111 filename_from_ansi (tem, dir_static.d_name);
3115 dir_static.d_namlen = strlen (dir_static.d_name);
3116 dir_static.d_reclen = sizeof (struct dirent) - MAX_UTF8_PATH + 3 +
3117 dir_static.d_namlen - dir_static.d_namlen % 4;
3119 return &dir_static;
3122 static HANDLE
3123 open_unc_volume (const char *path)
3125 const char *fn = map_w32_filename (path, NULL);
3126 DWORD result;
3127 HANDLE henum;
3129 if (w32_unicode_filenames)
3131 NETRESOURCEW nrw;
3132 wchar_t fnw[MAX_PATH];
3134 nrw.dwScope = RESOURCE_GLOBALNET;
3135 nrw.dwType = RESOURCETYPE_DISK;
3136 nrw.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
3137 nrw.dwUsage = RESOURCEUSAGE_CONTAINER;
3138 nrw.lpLocalName = NULL;
3139 filename_to_utf16 (fn, fnw);
3140 nrw.lpRemoteName = fnw;
3141 nrw.lpComment = NULL;
3142 nrw.lpProvider = NULL;
3144 result = WNetOpenEnumW (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
3145 RESOURCEUSAGE_CONNECTABLE, &nrw, &henum);
3147 else
3149 NETRESOURCEA nra;
3150 char fna[MAX_PATH];
3152 nra.dwScope = RESOURCE_GLOBALNET;
3153 nra.dwType = RESOURCETYPE_DISK;
3154 nra.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
3155 nra.dwUsage = RESOURCEUSAGE_CONTAINER;
3156 nra.lpLocalName = NULL;
3157 filename_to_ansi (fn, fna);
3158 nra.lpRemoteName = fna;
3159 nra.lpComment = NULL;
3160 nra.lpProvider = NULL;
3162 result = WNetOpenEnumA (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
3163 RESOURCEUSAGE_CONNECTABLE, &nra, &henum);
3165 if (result == NO_ERROR)
3166 return henum;
3167 else
3168 return INVALID_HANDLE_VALUE;
3171 static void *
3172 read_unc_volume (HANDLE henum, wchar_t *fname_w, char *fname_a, int size)
3174 DWORD count;
3175 int result;
3176 char *buffer;
3177 DWORD bufsize = 512;
3178 void *retval;
3180 count = 1;
3181 if (w32_unicode_filenames)
3183 wchar_t *ptrw;
3185 bufsize *= 2;
3186 buffer = alloca (bufsize);
3187 result = WNetEnumResourceW (henum, &count, buffer, &bufsize);
3188 if (result != NO_ERROR)
3189 return NULL;
3190 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
3191 ptrw = ((LPNETRESOURCEW) buffer)->lpRemoteName;
3192 ptrw += 2;
3193 while (*ptrw && *ptrw != L'/' && *ptrw != L'\\') ptrw++;
3194 ptrw++;
3195 wcsncpy (fname_w, ptrw, size);
3196 retval = fname_w;
3198 else
3200 int dbcs_p = max_filename_mbslen () > 1;
3201 char *ptra;
3203 buffer = alloca (bufsize);
3204 result = WNetEnumResourceA (henum, &count, buffer, &bufsize);
3205 if (result != NO_ERROR)
3206 return NULL;
3207 ptra = ((LPNETRESOURCEA) buffer)->lpRemoteName;
3208 ptra += 2;
3209 if (!dbcs_p)
3210 while (*ptra && !IS_DIRECTORY_SEP (*ptra)) ptra++;
3211 else
3213 while (*ptra && !IS_DIRECTORY_SEP (*ptra))
3214 ptra = CharNextExA (file_name_codepage, ptra, 0);
3216 ptra++;
3217 strncpy (fname_a, ptra, size);
3218 retval = fname_a;
3221 return retval;
3224 static void
3225 close_unc_volume (HANDLE henum)
3227 if (henum != INVALID_HANDLE_VALUE)
3228 WNetCloseEnum (henum);
3231 static DWORD
3232 unc_volume_file_attributes (const char *path)
3234 HANDLE henum;
3235 DWORD attrs;
3237 henum = open_unc_volume (path);
3238 if (henum == INVALID_HANDLE_VALUE)
3239 return -1;
3241 attrs = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY;
3243 close_unc_volume (henum);
3245 return attrs;
3248 /* Ensure a network connection is authenticated. */
3249 static void
3250 logon_network_drive (const char *path)
3252 char share[MAX_UTF8_PATH];
3253 int n_slashes;
3254 char drive[4];
3255 UINT drvtype;
3256 char *p;
3257 DWORD val;
3259 if (IS_DIRECTORY_SEP (path[0]) && IS_DIRECTORY_SEP (path[1]))
3260 drvtype = DRIVE_REMOTE;
3261 else if (path[0] == '\0' || path[1] != ':')
3262 drvtype = GetDriveType (NULL);
3263 else
3265 drive[0] = path[0];
3266 drive[1] = ':';
3267 drive[2] = '\\';
3268 drive[3] = '\0';
3269 drvtype = GetDriveType (drive);
3272 /* Only logon to networked drives. */
3273 if (drvtype != DRIVE_REMOTE)
3274 return;
3276 n_slashes = 2;
3277 strncpy (share, path, MAX_UTF8_PATH);
3278 /* Truncate to just server and share name. */
3279 for (p = share + 2; *p && p < share + MAX_UTF8_PATH; p++)
3281 if (IS_DIRECTORY_SEP (*p) && ++n_slashes > 3)
3283 *p = '\0';
3284 break;
3288 if (w32_unicode_filenames)
3290 NETRESOURCEW resourcew;
3291 wchar_t share_w[MAX_PATH];
3293 resourcew.dwScope = RESOURCE_GLOBALNET;
3294 resourcew.dwType = RESOURCETYPE_DISK;
3295 resourcew.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
3296 resourcew.dwUsage = RESOURCEUSAGE_CONTAINER;
3297 resourcew.lpLocalName = NULL;
3298 filename_to_utf16 (share, share_w);
3299 resourcew.lpRemoteName = share_w;
3300 resourcew.lpProvider = NULL;
3302 val = WNetAddConnection2W (&resourcew, NULL, NULL, CONNECT_INTERACTIVE);
3304 else
3306 NETRESOURCEA resourcea;
3307 char share_a[MAX_PATH];
3309 resourcea.dwScope = RESOURCE_GLOBALNET;
3310 resourcea.dwType = RESOURCETYPE_DISK;
3311 resourcea.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
3312 resourcea.dwUsage = RESOURCEUSAGE_CONTAINER;
3313 resourcea.lpLocalName = NULL;
3314 filename_to_ansi (share, share_a);
3315 resourcea.lpRemoteName = share_a;
3316 resourcea.lpProvider = NULL;
3318 val = WNetAddConnection2A (&resourcea, NULL, NULL, CONNECT_INTERACTIVE);
3321 switch (val)
3323 case NO_ERROR:
3324 case ERROR_ALREADY_ASSIGNED:
3325 break;
3326 case ERROR_ACCESS_DENIED:
3327 case ERROR_LOGON_FAILURE:
3328 errno = EACCES;
3329 break;
3330 case ERROR_BUSY:
3331 errno = EAGAIN;
3332 break;
3333 case ERROR_BAD_NET_NAME:
3334 case ERROR_NO_NET_OR_BAD_PATH:
3335 case ERROR_NO_NETWORK:
3336 case ERROR_CANCELLED:
3337 default:
3338 errno = ENOENT;
3339 break;
3343 /* Emulate faccessat(2). */
3345 faccessat (int dirfd, const char * path, int mode, int flags)
3347 DWORD attributes;
3349 if (dirfd != AT_FDCWD
3350 && !(IS_DIRECTORY_SEP (path[0])
3351 || IS_DEVICE_SEP (path[1])))
3353 errno = EBADF;
3354 return -1;
3357 /* MSVCRT implementation of 'access' doesn't recognize D_OK, and its
3358 newer versions blow up when passed D_OK. */
3359 path = map_w32_filename (path, NULL);
3360 /* If the last element of PATH is a symlink, we need to resolve it
3361 to get the attributes of its target file. Note: any symlinks in
3362 PATH elements other than the last one are transparently resolved
3363 by GetFileAttributes below. */
3364 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0
3365 && (flags & AT_SYMLINK_NOFOLLOW) == 0)
3366 path = chase_symlinks (path);
3368 if ((attributes = GetFileAttributes (path)) == -1)
3370 DWORD w32err = GetLastError ();
3372 switch (w32err)
3374 case ERROR_INVALID_NAME:
3375 case ERROR_BAD_PATHNAME:
3376 if (is_unc_volume (path))
3378 attributes = unc_volume_file_attributes (path);
3379 if (attributes == -1)
3381 errno = EACCES;
3382 return -1;
3384 break;
3386 /* FALLTHROUGH */
3387 case ERROR_FILE_NOT_FOUND:
3388 case ERROR_BAD_NETPATH:
3389 errno = ENOENT;
3390 break;
3391 default:
3392 errno = EACCES;
3393 break;
3395 return -1;
3397 if ((mode & X_OK) != 0
3398 && !(is_exec (path) || (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0))
3400 errno = EACCES;
3401 return -1;
3403 if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0)
3405 errno = EACCES;
3406 return -1;
3408 if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
3410 errno = EACCES;
3411 return -1;
3413 return 0;
3416 /* A version of 'access' to be used locally with file names in
3417 locale-specific encoding. Does not resolve symlinks and does not
3418 support file names on FAT12 and FAT16 volumes, but that's OK, since
3419 we only invoke this function for files inside the Emacs source or
3420 installation tree, on directories (so any symlinks should have the
3421 directory bit set), and on short file names such as "C:/.emacs". */
3422 static int
3423 sys_access (const char *fname, int mode)
3425 char fname_copy[MAX_PATH], *p;
3426 DWORD attributes;
3428 strcpy (fname_copy, fname);
3429 /* Do the equivalent of unixtodos_filename. */
3430 for (p = fname_copy; *p; p = CharNext (p))
3431 if (*p == '/')
3432 *p = '\\';
3434 if ((attributes = GetFileAttributesA (fname_copy)) == -1)
3436 DWORD w32err = GetLastError ();
3438 switch (w32err)
3440 case ERROR_INVALID_NAME:
3441 case ERROR_BAD_PATHNAME:
3442 case ERROR_FILE_NOT_FOUND:
3443 case ERROR_BAD_NETPATH:
3444 errno = ENOENT;
3445 break;
3446 default:
3447 errno = EACCES;
3448 break;
3450 return -1;
3452 if ((mode & X_OK) != 0
3453 && !(is_exec (fname_copy)
3454 || (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0))
3456 errno = EACCES;
3457 return -1;
3459 if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0)
3461 errno = EACCES;
3462 return -1;
3464 if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
3466 errno = EACCES;
3467 return -1;
3469 return 0;
3472 /* Shadow some MSVC runtime functions to map requests for long filenames
3473 to reasonable short names if necessary. This was originally added to
3474 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
3475 long file names. */
3478 sys_chdir (const char * path)
3480 /* FIXME: Temporary. Also, figure out what to do with
3481 map_w32_filename, as the original code did this:
3482 _chdir(map_w32_filename (path, NULL)). */
3483 if (w32_unicode_filenames)
3485 wchar_t newdir[MAXPATHLEN];
3487 if (filename_to_utf16 (path, newdir) == 0)
3488 return _wchdir (newdir);
3489 return -1;
3491 else
3493 char newdir[MAXPATHLEN];
3495 if (filename_to_ansi (path, newdir) == 0)
3496 return _chdir (path);
3497 return -1;
3502 sys_chmod (const char * path, int mode)
3504 path = chase_symlinks (map_w32_filename (path, NULL));
3505 return _chmod (path, mode);
3509 sys_creat (const char * path, int mode)
3511 return _creat (map_w32_filename (path, NULL), mode);
3514 FILE *
3515 sys_fopen (const char * path, const char * mode)
3517 int fd;
3518 int oflag;
3519 const char * mode_save = mode;
3521 /* Force all file handles to be non-inheritable. This is necessary to
3522 ensure child processes don't unwittingly inherit handles that might
3523 prevent future file access. */
3525 if (mode[0] == 'r')
3526 oflag = O_RDONLY;
3527 else if (mode[0] == 'w' || mode[0] == 'a')
3528 oflag = O_WRONLY | O_CREAT | O_TRUNC;
3529 else
3530 return NULL;
3532 /* Only do simplistic option parsing. */
3533 while (*++mode)
3534 if (mode[0] == '+')
3536 oflag &= ~(O_RDONLY | O_WRONLY);
3537 oflag |= O_RDWR;
3539 else if (mode[0] == 'b')
3541 oflag &= ~O_TEXT;
3542 oflag |= O_BINARY;
3544 else if (mode[0] == 't')
3546 oflag &= ~O_BINARY;
3547 oflag |= O_TEXT;
3549 else break;
3551 fd = _open (map_w32_filename (path, NULL), oflag | _O_NOINHERIT, 0644);
3552 if (fd < 0)
3553 return NULL;
3555 return _fdopen (fd, mode_save);
3558 /* This only works on NTFS volumes, but is useful to have. */
3560 sys_link (const char * old, const char * new)
3562 HANDLE fileh;
3563 int result = -1;
3564 char oldname[MAX_PATH], newname[MAX_PATH];
3566 if (old == NULL || new == NULL)
3568 errno = ENOENT;
3569 return -1;
3572 strcpy (oldname, map_w32_filename (old, NULL));
3573 strcpy (newname, map_w32_filename (new, NULL));
3575 fileh = CreateFile (oldname, 0, 0, NULL, OPEN_EXISTING,
3576 FILE_FLAG_BACKUP_SEMANTICS, NULL);
3577 if (fileh != INVALID_HANDLE_VALUE)
3579 int wlen;
3581 /* Confusingly, the "alternate" stream name field does not apply
3582 when restoring a hard link, and instead contains the actual
3583 stream data for the link (ie. the name of the link to create).
3584 The WIN32_STREAM_ID structure before the cStreamName field is
3585 the stream header, which is then immediately followed by the
3586 stream data. */
3588 struct {
3589 WIN32_STREAM_ID wid;
3590 WCHAR wbuffer[MAX_PATH]; /* extra space for link name */
3591 } data;
3593 wlen = MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, newname, -1,
3594 data.wid.cStreamName, MAX_PATH);
3595 if (wlen > 0)
3597 LPVOID context = NULL;
3598 DWORD wbytes = 0;
3600 data.wid.dwStreamId = BACKUP_LINK;
3601 data.wid.dwStreamAttributes = 0;
3602 data.wid.Size.LowPart = wlen * sizeof (WCHAR);
3603 data.wid.Size.HighPart = 0;
3604 data.wid.dwStreamNameSize = 0;
3606 if (BackupWrite (fileh, (LPBYTE)&data,
3607 offsetof (WIN32_STREAM_ID, cStreamName)
3608 + data.wid.Size.LowPart,
3609 &wbytes, FALSE, FALSE, &context)
3610 && BackupWrite (fileh, NULL, 0, &wbytes, TRUE, FALSE, &context))
3612 /* succeeded */
3613 result = 0;
3615 else
3617 /* Should try mapping GetLastError to errno; for now just
3618 indicate a general error (eg. links not supported). */
3619 errno = EINVAL; // perhaps EMLINK?
3623 CloseHandle (fileh);
3625 else
3626 errno = ENOENT;
3628 return result;
3632 sys_mkdir (const char * path)
3634 return _mkdir (map_w32_filename (path, NULL));
3638 sys_open (const char * path, int oflag, int mode)
3640 const char* mpath = map_w32_filename (path, NULL);
3641 int res = -1;
3643 /* If possible, try to open file without _O_CREAT, to be able to
3644 write to existing hidden and system files. Force all file
3645 handles to be non-inheritable. */
3646 if ((oflag & (_O_CREAT | _O_EXCL)) != (_O_CREAT | _O_EXCL))
3647 res = _open (mpath, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
3648 if (res < 0)
3649 res = _open (mpath, oflag | _O_NOINHERIT, mode);
3651 return res;
3654 /* Implementation of mkostemp for MS-Windows, to avoid race conditions
3655 when using mktemp.
3657 Standard algorithm for generating a temporary file name seems to be
3658 use pid or tid with a letter on the front (in place of the 6 X's)
3659 and cycle through the letters to find a unique name. We extend
3660 that to allow any reasonable character as the first of the 6 X's,
3661 so that the number of simultaneously used temporary files will be
3662 greater. */
3665 mkostemp (char * template, int flags)
3667 char * p;
3668 int i, fd = -1;
3669 unsigned uid = GetCurrentThreadId ();
3670 int save_errno = errno;
3671 static char first_char[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
3673 errno = EINVAL;
3674 if (template == NULL)
3675 return -1;
3677 p = template + strlen (template);
3678 i = 5;
3679 /* replace up to the last 5 X's with uid in decimal */
3680 while (--p >= template && p[0] == 'X' && --i >= 0)
3682 p[0] = '0' + uid % 10;
3683 uid /= 10;
3686 if (i < 0 && p[0] == 'X')
3688 i = 0;
3691 p[0] = first_char[i];
3692 if ((fd = sys_open (template,
3693 flags | _O_CREAT | _O_EXCL | _O_RDWR,
3694 S_IRUSR | S_IWUSR)) >= 0
3695 || errno != EEXIST)
3697 if (fd >= 0)
3698 errno = save_errno;
3699 return fd;
3702 while (++i < sizeof (first_char));
3705 /* Template is badly formed or else we can't generate a unique name. */
3706 return -1;
3710 fchmod (int fd, mode_t mode)
3712 return 0;
3716 sys_rename_replace (const char *oldname, const char *newname, BOOL force)
3718 BOOL result;
3719 char temp[MAX_PATH];
3720 int newname_dev;
3721 int oldname_dev;
3723 /* MoveFile on Windows 95 doesn't correctly change the short file name
3724 alias in a number of circumstances (it is not easy to predict when
3725 just by looking at oldname and newname, unfortunately). In these
3726 cases, renaming through a temporary name avoids the problem.
3728 A second problem on Windows 95 is that renaming through a temp name when
3729 newname is uppercase fails (the final long name ends up in
3730 lowercase, although the short alias might be uppercase) UNLESS the
3731 long temp name is not 8.3.
3733 So, on Windows 95 we always rename through a temp name, and we make sure
3734 the temp name has a long extension to ensure correct renaming. */
3736 strcpy (temp, map_w32_filename (oldname, NULL));
3738 /* volume_info is set indirectly by map_w32_filename. */
3739 oldname_dev = volume_info.serialnum;
3741 if (os_subtype == OS_9X)
3743 char * o;
3744 char * p;
3745 int i = 0;
3747 oldname = map_w32_filename (oldname, NULL);
3748 if ((o = strrchr (oldname, '\\')))
3749 o++;
3750 else
3751 o = (char *) oldname;
3753 if ((p = strrchr (temp, '\\')))
3754 p++;
3755 else
3756 p = temp;
3760 /* Force temp name to require a manufactured 8.3 alias - this
3761 seems to make the second rename work properly. */
3762 sprintf (p, "_.%s.%u", o, i);
3763 i++;
3764 result = rename (oldname, temp);
3766 /* This loop must surely terminate! */
3767 while (result < 0 && errno == EEXIST);
3768 if (result < 0)
3769 return -1;
3772 /* If FORCE, emulate Unix behavior - newname is deleted if it already exists
3773 (at least if it is a file; don't do this for directories).
3775 Since we mustn't do this if we are just changing the case of the
3776 file name (we would end up deleting the file we are trying to
3777 rename!), we let rename detect if the destination file already
3778 exists - that way we avoid the possible pitfalls of trying to
3779 determine ourselves whether two names really refer to the same
3780 file, which is not always possible in the general case. (Consider
3781 all the permutations of shared or subst'd drives, etc.) */
3783 newname = map_w32_filename (newname, NULL);
3785 /* volume_info is set indirectly by map_w32_filename. */
3786 newname_dev = volume_info.serialnum;
3788 result = rename (temp, newname);
3790 if (result < 0 && force)
3792 DWORD w32err = GetLastError ();
3794 if (errno == EACCES
3795 && newname_dev != oldname_dev)
3797 /* The implementation of `rename' on Windows does not return
3798 errno = EXDEV when you are moving a directory to a
3799 different storage device (ex. logical disk). It returns
3800 EACCES instead. So here we handle such situations and
3801 return EXDEV. */
3802 DWORD attributes;
3804 if ((attributes = GetFileAttributes (temp)) != -1
3805 && (attributes & FILE_ATTRIBUTE_DIRECTORY))
3806 errno = EXDEV;
3808 else if (errno == EEXIST)
3810 if (_chmod (newname, 0666) != 0)
3811 return result;
3812 if (_unlink (newname) != 0)
3813 return result;
3814 result = rename (temp, newname);
3816 else if (w32err == ERROR_PRIVILEGE_NOT_HELD
3817 && is_symlink (temp))
3819 /* This is Windows prohibiting the user from creating a
3820 symlink in another place, since that requires
3821 privileges. */
3822 errno = EPERM;
3826 return result;
3830 sys_rename (char const *old, char const *new)
3832 return sys_rename_replace (old, new, TRUE);
3836 sys_rmdir (const char * path)
3838 return _rmdir (map_w32_filename (path, NULL));
3842 sys_unlink (const char * path)
3844 path = map_w32_filename (path, NULL);
3846 /* On Unix, unlink works without write permission. */
3847 _chmod (path, 0666);
3848 return _unlink (path);
3851 static FILETIME utc_base_ft;
3852 static ULONGLONG utc_base; /* In 100ns units */
3853 static int init = 0;
3855 #define FILETIME_TO_U64(result, ft) \
3856 do { \
3857 ULARGE_INTEGER uiTemp; \
3858 uiTemp.LowPart = (ft).dwLowDateTime; \
3859 uiTemp.HighPart = (ft).dwHighDateTime; \
3860 result = uiTemp.QuadPart; \
3861 } while (0)
3863 static void
3864 initialize_utc_base (void)
3866 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
3867 SYSTEMTIME st;
3869 st.wYear = 1970;
3870 st.wMonth = 1;
3871 st.wDay = 1;
3872 st.wHour = 0;
3873 st.wMinute = 0;
3874 st.wSecond = 0;
3875 st.wMilliseconds = 0;
3877 SystemTimeToFileTime (&st, &utc_base_ft);
3878 FILETIME_TO_U64 (utc_base, utc_base_ft);
3881 static time_t
3882 convert_time (FILETIME ft)
3884 ULONGLONG tmp;
3886 if (!init)
3888 initialize_utc_base ();
3889 init = 1;
3892 if (CompareFileTime (&ft, &utc_base_ft) < 0)
3893 return 0;
3895 FILETIME_TO_U64 (tmp, ft);
3896 return (time_t) ((tmp - utc_base) / 10000000L);
3899 static void
3900 convert_from_time_t (time_t time, FILETIME * pft)
3902 ULARGE_INTEGER tmp;
3904 if (!init)
3906 initialize_utc_base ();
3907 init = 1;
3910 /* time in 100ns units since 1-Jan-1601 */
3911 tmp.QuadPart = (ULONGLONG) time * 10000000L + utc_base;
3912 pft->dwHighDateTime = tmp.HighPart;
3913 pft->dwLowDateTime = tmp.LowPart;
3916 static PSECURITY_DESCRIPTOR
3917 get_file_security_desc_by_handle (HANDLE h)
3919 PSECURITY_DESCRIPTOR psd = NULL;
3920 DWORD err;
3921 SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION
3922 | GROUP_SECURITY_INFORMATION /* | DACL_SECURITY_INFORMATION */ ;
3924 err = get_security_info (h, SE_FILE_OBJECT, si,
3925 NULL, NULL, NULL, NULL, &psd);
3926 if (err != ERROR_SUCCESS)
3927 return NULL;
3929 return psd;
3932 static PSECURITY_DESCRIPTOR
3933 get_file_security_desc_by_name (const char *fname)
3935 PSECURITY_DESCRIPTOR psd = NULL;
3936 DWORD sd_len, err;
3937 SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION
3938 | GROUP_SECURITY_INFORMATION /* | DACL_SECURITY_INFORMATION */ ;
3940 if (!get_file_security (fname, si, psd, 0, &sd_len))
3942 err = GetLastError ();
3943 if (err != ERROR_INSUFFICIENT_BUFFER)
3944 return NULL;
3947 psd = xmalloc (sd_len);
3948 if (!get_file_security (fname, si, psd, sd_len, &sd_len))
3950 xfree (psd);
3951 return NULL;
3954 return psd;
3957 static DWORD
3958 get_rid (PSID sid)
3960 unsigned n_subauthorities;
3962 /* Use the last sub-authority value of the RID, the relative
3963 portion of the SID, as user/group ID. */
3964 n_subauthorities = *get_sid_sub_authority_count (sid);
3965 if (n_subauthorities < 1)
3966 return 0; /* the "World" RID */
3967 return *get_sid_sub_authority (sid, n_subauthorities - 1);
3970 /* Caching SID and account values for faster lokup. */
3972 struct w32_id {
3973 unsigned rid;
3974 struct w32_id *next;
3975 char name[GNLEN+1];
3976 unsigned char sid[FLEXIBLE_ARRAY_MEMBER];
3979 static struct w32_id *w32_idlist;
3981 static int
3982 w32_cached_id (PSID sid, unsigned *id, char *name)
3984 struct w32_id *tail, *found;
3986 for (found = NULL, tail = w32_idlist; tail; tail = tail->next)
3988 if (equal_sid ((PSID)tail->sid, sid))
3990 found = tail;
3991 break;
3994 if (found)
3996 *id = found->rid;
3997 strcpy (name, found->name);
3998 return 1;
4000 else
4001 return 0;
4004 static void
4005 w32_add_to_cache (PSID sid, unsigned id, char *name)
4007 DWORD sid_len;
4008 struct w32_id *new_entry;
4010 /* We don't want to leave behind stale cache from when Emacs was
4011 dumped. */
4012 if (initialized)
4014 sid_len = get_length_sid (sid);
4015 new_entry = xmalloc (offsetof (struct w32_id, sid) + sid_len);
4016 if (new_entry)
4018 new_entry->rid = id;
4019 strcpy (new_entry->name, name);
4020 copy_sid (sid_len, (PSID)new_entry->sid, sid);
4021 new_entry->next = w32_idlist;
4022 w32_idlist = new_entry;
4027 #define UID 1
4028 #define GID 2
4030 static int
4031 get_name_and_id (PSECURITY_DESCRIPTOR psd, unsigned *id, char *nm, int what)
4033 PSID sid = NULL;
4034 BOOL dflt;
4035 SID_NAME_USE ignore;
4036 char name[UNLEN+1];
4037 DWORD name_len = sizeof (name);
4038 char domain[1024];
4039 DWORD domain_len = sizeof (domain);
4040 int use_dflt = 0;
4041 int result;
4043 if (what == UID)
4044 result = get_security_descriptor_owner (psd, &sid, &dflt);
4045 else if (what == GID)
4046 result = get_security_descriptor_group (psd, &sid, &dflt);
4047 else
4048 result = 0;
4050 if (!result || !is_valid_sid (sid))
4051 use_dflt = 1;
4052 else if (!w32_cached_id (sid, id, nm))
4054 if (!lookup_account_sid (NULL, sid, name, &name_len,
4055 domain, &domain_len, &ignore)
4056 || name_len > UNLEN+1)
4057 use_dflt = 1;
4058 else
4060 *id = get_rid (sid);
4061 strcpy (nm, name);
4062 w32_add_to_cache (sid, *id, name);
4065 return use_dflt;
4068 static void
4069 get_file_owner_and_group (PSECURITY_DESCRIPTOR psd, struct stat *st)
4071 int dflt_usr = 0, dflt_grp = 0;
4073 if (!psd)
4075 dflt_usr = 1;
4076 dflt_grp = 1;
4078 else
4080 if (get_name_and_id (psd, &st->st_uid, st->st_uname, UID))
4081 dflt_usr = 1;
4082 if (get_name_and_id (psd, &st->st_gid, st->st_gname, GID))
4083 dflt_grp = 1;
4085 /* Consider files to belong to current user/group, if we cannot get
4086 more accurate information. */
4087 if (dflt_usr)
4089 st->st_uid = dflt_passwd.pw_uid;
4090 strcpy (st->st_uname, dflt_passwd.pw_name);
4092 if (dflt_grp)
4094 st->st_gid = dflt_passwd.pw_gid;
4095 strcpy (st->st_gname, dflt_group.gr_name);
4099 /* Return non-zero if NAME is a potentially slow filesystem. */
4101 is_slow_fs (const char *name)
4103 char drive_root[4];
4104 UINT devtype;
4106 if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
4107 devtype = DRIVE_REMOTE; /* assume UNC name is remote */
4108 else if (!(strlen (name) >= 2 && IS_DEVICE_SEP (name[1])))
4109 devtype = GetDriveType (NULL); /* use root of current drive */
4110 else
4112 /* GetDriveType needs the root directory of the drive. */
4113 strncpy (drive_root, name, 2);
4114 drive_root[2] = '\\';
4115 drive_root[3] = '\0';
4116 devtype = GetDriveType (drive_root);
4118 return !(devtype == DRIVE_FIXED || devtype == DRIVE_RAMDISK);
4121 /* If this is non-zero, the caller wants accurate information about
4122 file's owner and group, which could be expensive to get. */
4123 int w32_stat_get_owner_group;
4125 /* MSVC stat function can't cope with UNC names and has other bugs, so
4126 replace it with our own. This also allows us to calculate consistent
4127 inode values and owner/group without hacks in the main Emacs code. */
4129 static int
4130 stat_worker (const char * path, struct stat * buf, int follow_symlinks)
4132 char *name, *save_name, *r;
4133 WIN32_FIND_DATA wfd;
4134 HANDLE fh;
4135 unsigned __int64 fake_inode = 0;
4136 int permission;
4137 int len;
4138 int rootdir = FALSE;
4139 PSECURITY_DESCRIPTOR psd = NULL;
4140 int is_a_symlink = 0;
4141 DWORD file_flags = FILE_FLAG_BACKUP_SEMANTICS;
4142 DWORD access_rights = 0;
4143 DWORD fattrs = 0, serialnum = 0, fs_high = 0, fs_low = 0, nlinks = 1;
4144 FILETIME ctime, atime, wtime;
4145 int dbcs_p;
4147 if (path == NULL || buf == NULL)
4149 errno = EFAULT;
4150 return -1;
4153 save_name = name = (char *) map_w32_filename (path, &path);
4154 /* Must be valid filename, no wild cards or other invalid
4155 characters. We use _mbspbrk to support multibyte strings that
4156 might look to strpbrk as if they included literal *, ?, and other
4157 characters mentioned below that are disallowed by Windows
4158 filesystems. */
4159 if (_mbspbrk (name, "*?|<>\""))
4161 errno = ENOENT;
4162 return -1;
4165 /* Remove trailing directory separator, unless name is the root
4166 directory of a drive or UNC volume in which case ensure there
4167 is a trailing separator. */
4168 len = strlen (name);
4169 name = strcpy (alloca (len + 2), name);
4171 /* Avoid a somewhat costly call to is_symlink if the filesystem
4172 doesn't support symlinks. */
4173 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
4174 is_a_symlink = is_symlink (name);
4176 /* Plan A: Open the file and get all the necessary information via
4177 the resulting handle. This solves several issues in one blow:
4179 . retrieves attributes for the target of a symlink, if needed
4180 . gets attributes of root directories and symlinks pointing to
4181 root directories, thus avoiding the need for special-casing
4182 these and detecting them by examining the file-name format
4183 . retrieves more accurate attributes (e.g., non-zero size for
4184 some directories, esp. directories that are junction points)
4185 . correctly resolves "c:/..", "/.." and similar file names
4186 . avoids run-time penalties for 99% of use cases
4188 Plan A is always tried first, unless the user asked not to (but
4189 if the file is a symlink and we need to follow links, we try Plan
4190 A even if the user asked not to).
4192 If Plan A fails, we go to Plan B (below), where various
4193 potentially expensive techniques must be used to handle "special"
4194 files such as UNC volumes etc. */
4195 if (!(NILP (Vw32_get_true_file_attributes)
4196 || (EQ (Vw32_get_true_file_attributes, Qlocal) && is_slow_fs (name)))
4197 /* Following symlinks requires getting the info by handle. */
4198 || (is_a_symlink && follow_symlinks))
4200 BY_HANDLE_FILE_INFORMATION info;
4202 if (is_a_symlink && !follow_symlinks)
4203 file_flags |= FILE_FLAG_OPEN_REPARSE_POINT;
4204 /* READ_CONTROL access rights are required to get security info
4205 by handle. But if the OS doesn't support security in the
4206 first place, we don't need to try. */
4207 if (is_windows_9x () != TRUE)
4208 access_rights |= READ_CONTROL;
4210 fh = CreateFile (name, access_rights, 0, NULL, OPEN_EXISTING,
4211 file_flags, NULL);
4212 /* If CreateFile fails with READ_CONTROL, try again with zero as
4213 access rights. */
4214 if (fh == INVALID_HANDLE_VALUE && access_rights)
4215 fh = CreateFile (name, 0, 0, NULL, OPEN_EXISTING,
4216 file_flags, NULL);
4217 if (fh == INVALID_HANDLE_VALUE)
4218 goto no_true_file_attributes;
4220 /* This is more accurate in terms of getting the correct number
4221 of links, but is quite slow (it is noticeable when Emacs is
4222 making a list of file name completions). */
4223 if (GetFileInformationByHandle (fh, &info))
4225 nlinks = info.nNumberOfLinks;
4226 /* Might as well use file index to fake inode values, but this
4227 is not guaranteed to be unique unless we keep a handle open
4228 all the time (even then there are situations where it is
4229 not unique). Reputedly, there are at most 48 bits of info
4230 (on NTFS, presumably less on FAT). */
4231 fake_inode = info.nFileIndexHigh;
4232 fake_inode <<= 32;
4233 fake_inode += info.nFileIndexLow;
4234 serialnum = info.dwVolumeSerialNumber;
4235 fs_high = info.nFileSizeHigh;
4236 fs_low = info.nFileSizeLow;
4237 ctime = info.ftCreationTime;
4238 atime = info.ftLastAccessTime;
4239 wtime = info.ftLastWriteTime;
4240 fattrs = info.dwFileAttributes;
4242 else
4244 /* We don't go to Plan B here, because it's not clear that
4245 it's a good idea. The only known use case where
4246 CreateFile succeeds, but GetFileInformationByHandle fails
4247 (with ERROR_INVALID_FUNCTION) is for character devices
4248 such as NUL, PRN, etc. For these, switching to Plan B is
4249 a net loss, because we lose the character device
4250 attribute returned by GetFileType below (FindFirstFile
4251 doesn't set that bit in the attributes), and the other
4252 fields don't make sense for character devices anyway.
4253 Emacs doesn't really care for non-file entities in the
4254 context of l?stat, so neither do we. */
4256 /* w32err is assigned so one could put a breakpoint here and
4257 examine its value, when GetFileInformationByHandle
4258 fails. */
4259 DWORD w32err = GetLastError ();
4261 switch (w32err)
4263 case ERROR_FILE_NOT_FOUND: /* can this ever happen? */
4264 errno = ENOENT;
4265 return -1;
4269 /* Test for a symlink before testing for a directory, since
4270 symlinks to directories have the directory bit set, but we
4271 don't want them to appear as directories. */
4272 if (is_a_symlink && !follow_symlinks)
4273 buf->st_mode = S_IFLNK;
4274 else if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
4275 buf->st_mode = S_IFDIR;
4276 else
4278 DWORD ftype = GetFileType (fh);
4280 switch (ftype)
4282 case FILE_TYPE_DISK:
4283 buf->st_mode = S_IFREG;
4284 break;
4285 case FILE_TYPE_PIPE:
4286 buf->st_mode = S_IFIFO;
4287 break;
4288 case FILE_TYPE_CHAR:
4289 case FILE_TYPE_UNKNOWN:
4290 default:
4291 buf->st_mode = S_IFCHR;
4294 /* We produce the fallback owner and group data, based on the
4295 current user that runs Emacs, in the following cases:
4297 . caller didn't request owner and group info
4298 . this is Windows 9X
4299 . getting security by handle failed, and we need to produce
4300 information for the target of a symlink (this is better
4301 than producing a potentially misleading info about the
4302 symlink itself)
4304 If getting security by handle fails, and we don't need to
4305 resolve symlinks, we try getting security by name. */
4306 if (!w32_stat_get_owner_group || is_windows_9x () == TRUE)
4307 get_file_owner_and_group (NULL, buf);
4308 else
4310 psd = get_file_security_desc_by_handle (fh);
4311 if (psd)
4313 get_file_owner_and_group (psd, buf);
4314 LocalFree (psd);
4316 else if (!(is_a_symlink && follow_symlinks))
4318 psd = get_file_security_desc_by_name (name);
4319 get_file_owner_and_group (psd, buf);
4320 xfree (psd);
4322 else
4323 get_file_owner_and_group (NULL, buf);
4325 CloseHandle (fh);
4327 else
4329 no_true_file_attributes:
4330 /* Plan B: Either getting a handle on the file failed, or the
4331 caller explicitly asked us to not bother making this
4332 information more accurate.
4334 Implementation note: In Plan B, we never bother to resolve
4335 symlinks, even if we got here because we tried Plan A and
4336 failed. That's because, even if the caller asked for extra
4337 precision by setting Vw32_get_true_file_attributes to t,
4338 resolving symlinks requires acquiring a file handle to the
4339 symlink, which we already know will fail. And if the user
4340 did not ask for extra precision, resolving symlinks will fly
4341 in the face of that request, since the user then wants the
4342 lightweight version of the code. */
4343 dbcs_p = max_filename_mbslen () > 1;
4344 rootdir = (path >= save_name + len - 1
4345 && (IS_DIRECTORY_SEP (*path) || *path == 0));
4347 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
4348 r = IS_DEVICE_SEP (name[1]) ? &name[2] : name;
4349 if (IS_DIRECTORY_SEP (r[0])
4350 && r[1] == '.' && r[2] == '.' && r[3] == '\0')
4351 r[1] = r[2] = '\0';
4353 /* Note: If NAME is a symlink to the root of a UNC volume
4354 (i.e. "\\SERVER"), we will not detect that here, and we will
4355 return data about the symlink as result of FindFirst below.
4356 This is unfortunate, but that marginal use case does not
4357 justify a call to chase_symlinks which would impose a penalty
4358 on all the other use cases. (We get here for symlinks to
4359 roots of UNC volumes because CreateFile above fails for them,
4360 unlike with symlinks to root directories X:\ of drives.) */
4361 if (is_unc_volume (name))
4363 fattrs = unc_volume_file_attributes (name);
4364 if (fattrs == -1)
4365 return -1;
4367 ctime = atime = wtime = utc_base_ft;
4369 else if (rootdir)
4371 if (!dbcs_p)
4373 if (!IS_DIRECTORY_SEP (name[len-1]))
4374 strcat (name, "\\");
4376 else
4378 char *end = name + len;
4379 char *n = CharPrevExA (file_name_codepage, name, end, 0);
4381 if (!IS_DIRECTORY_SEP (*n))
4382 strcat (name, "\\");
4384 if (GetDriveType (name) < 2)
4386 errno = ENOENT;
4387 return -1;
4390 fattrs = FILE_ATTRIBUTE_DIRECTORY;
4391 ctime = atime = wtime = utc_base_ft;
4393 else
4395 if (!dbcs_p)
4397 if (IS_DIRECTORY_SEP (name[len-1]))
4398 name[len - 1] = 0;
4400 else
4402 char *end = name + len;
4403 char *n = CharPrevExA (file_name_codepage, name, end, 0);
4405 if (IS_DIRECTORY_SEP (*n))
4406 *n = 0;
4409 /* (This is hacky, but helps when doing file completions on
4410 network drives.) Optimize by using information available from
4411 active readdir if possible. */
4412 len = strlen (dir_pathname);
4413 if (!dbcs_p)
4415 if (IS_DIRECTORY_SEP (dir_pathname[len-1]))
4416 len--;
4418 else
4420 char *end = dir_pathname + len;
4421 char *n = CharPrevExA (file_name_codepage, dir_pathname, end, 0);
4423 if (IS_DIRECTORY_SEP (*n))
4424 len--;
4426 if (dir_find_handle != INVALID_HANDLE_VALUE
4427 && !(is_a_symlink && follow_symlinks)
4428 && strnicmp (save_name, dir_pathname, len) == 0
4429 && IS_DIRECTORY_SEP (name[len])
4430 && xstrcasecmp (name + len + 1, dir_static.d_name) == 0)
4432 /* This was the last entry returned by readdir. */
4433 wfd = dir_find_data_a; /* FIXME!!! */
4435 else
4437 logon_network_drive (name);
4439 fh = FindFirstFile (name, &wfd);
4440 if (fh == INVALID_HANDLE_VALUE)
4442 errno = ENOENT;
4443 return -1;
4445 FindClose (fh);
4447 /* Note: if NAME is a symlink, the information we get from
4448 FindFirstFile is for the symlink, not its target. */
4449 fattrs = wfd.dwFileAttributes;
4450 ctime = wfd.ftCreationTime;
4451 atime = wfd.ftLastAccessTime;
4452 wtime = wfd.ftLastWriteTime;
4453 fs_high = wfd.nFileSizeHigh;
4454 fs_low = wfd.nFileSizeLow;
4455 fake_inode = 0;
4456 nlinks = 1;
4457 serialnum = volume_info.serialnum;
4459 if (is_a_symlink && !follow_symlinks)
4460 buf->st_mode = S_IFLNK;
4461 else if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
4462 buf->st_mode = S_IFDIR;
4463 else
4464 buf->st_mode = S_IFREG;
4466 get_file_owner_and_group (NULL, buf);
4469 #if 0
4470 /* Not sure if there is any point in this. */
4471 if (!NILP (Vw32_generate_fake_inodes))
4472 fake_inode = generate_inode_val (name);
4473 else if (fake_inode == 0)
4475 /* For want of something better, try to make everything unique. */
4476 static DWORD gen_num = 0;
4477 fake_inode = ++gen_num;
4479 #endif
4481 buf->st_ino = fake_inode;
4483 buf->st_dev = serialnum;
4484 buf->st_rdev = serialnum;
4486 buf->st_size = fs_high;
4487 buf->st_size <<= 32;
4488 buf->st_size += fs_low;
4489 buf->st_nlink = nlinks;
4491 /* Convert timestamps to Unix format. */
4492 buf->st_mtime = convert_time (wtime);
4493 buf->st_atime = convert_time (atime);
4494 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
4495 buf->st_ctime = convert_time (ctime);
4496 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
4498 /* determine rwx permissions */
4499 if (is_a_symlink && !follow_symlinks)
4500 permission = S_IREAD | S_IWRITE | S_IEXEC; /* Posix expectations */
4501 else
4503 if (fattrs & FILE_ATTRIBUTE_READONLY)
4504 permission = S_IREAD;
4505 else
4506 permission = S_IREAD | S_IWRITE;
4508 if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
4509 permission |= S_IEXEC;
4510 else if (is_exec (name))
4511 permission |= S_IEXEC;
4514 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
4516 return 0;
4520 stat (const char * path, struct stat * buf)
4522 return stat_worker (path, buf, 1);
4526 lstat (const char * path, struct stat * buf)
4528 return stat_worker (path, buf, 0);
4532 fstatat (int fd, char const *name, struct stat *st, int flags)
4534 /* Rely on a hack: an open directory is modeled as file descriptor 0.
4535 This is good enough for the current usage in Emacs, but is fragile.
4537 FIXME: Add proper support for fdopendir, fstatat, readlinkat.
4538 Gnulib does this and can serve as a model. */
4539 char fullname[MAX_PATH];
4541 if (fd != AT_FDCWD)
4543 if (_snprintf (fullname, sizeof fullname, "%s/%s", dir_pathname, name)
4544 < 0)
4546 errno = ENAMETOOLONG;
4547 return -1;
4549 name = fullname;
4552 return stat_worker (name, st, ! (flags & AT_SYMLINK_NOFOLLOW));
4555 /* Provide fstat and utime as well as stat for consistent handling of
4556 file timestamps. */
4558 fstat (int desc, struct stat * buf)
4560 HANDLE fh = (HANDLE) _get_osfhandle (desc);
4561 BY_HANDLE_FILE_INFORMATION info;
4562 unsigned __int64 fake_inode;
4563 int permission;
4565 switch (GetFileType (fh) & ~FILE_TYPE_REMOTE)
4567 case FILE_TYPE_DISK:
4568 buf->st_mode = S_IFREG;
4569 if (!GetFileInformationByHandle (fh, &info))
4571 errno = EACCES;
4572 return -1;
4574 break;
4575 case FILE_TYPE_PIPE:
4576 buf->st_mode = S_IFIFO;
4577 goto non_disk;
4578 case FILE_TYPE_CHAR:
4579 case FILE_TYPE_UNKNOWN:
4580 default:
4581 buf->st_mode = S_IFCHR;
4582 non_disk:
4583 memset (&info, 0, sizeof (info));
4584 info.dwFileAttributes = 0;
4585 info.ftCreationTime = utc_base_ft;
4586 info.ftLastAccessTime = utc_base_ft;
4587 info.ftLastWriteTime = utc_base_ft;
4590 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
4591 buf->st_mode = S_IFDIR;
4593 buf->st_nlink = info.nNumberOfLinks;
4594 /* Might as well use file index to fake inode values, but this
4595 is not guaranteed to be unique unless we keep a handle open
4596 all the time (even then there are situations where it is
4597 not unique). Reputedly, there are at most 48 bits of info
4598 (on NTFS, presumably less on FAT). */
4599 fake_inode = info.nFileIndexHigh;
4600 fake_inode <<= 32;
4601 fake_inode += info.nFileIndexLow;
4603 /* MSVC defines _ino_t to be short; other libc's might not. */
4604 if (sizeof (buf->st_ino) == 2)
4605 buf->st_ino = fake_inode ^ (fake_inode >> 16);
4606 else
4607 buf->st_ino = fake_inode;
4609 /* If the caller so requested, get the true file owner and group.
4610 Otherwise, consider the file to belong to the current user. */
4611 if (!w32_stat_get_owner_group || is_windows_9x () == TRUE)
4612 get_file_owner_and_group (NULL, buf);
4613 else
4615 PSECURITY_DESCRIPTOR psd = NULL;
4617 psd = get_file_security_desc_by_handle (fh);
4618 if (psd)
4620 get_file_owner_and_group (psd, buf);
4621 LocalFree (psd);
4623 else
4624 get_file_owner_and_group (NULL, buf);
4627 buf->st_dev = info.dwVolumeSerialNumber;
4628 buf->st_rdev = info.dwVolumeSerialNumber;
4630 buf->st_size = info.nFileSizeHigh;
4631 buf->st_size <<= 32;
4632 buf->st_size += info.nFileSizeLow;
4634 /* Convert timestamps to Unix format. */
4635 buf->st_mtime = convert_time (info.ftLastWriteTime);
4636 buf->st_atime = convert_time (info.ftLastAccessTime);
4637 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
4638 buf->st_ctime = convert_time (info.ftCreationTime);
4639 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
4641 /* determine rwx permissions */
4642 if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
4643 permission = S_IREAD;
4644 else
4645 permission = S_IREAD | S_IWRITE;
4647 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
4648 permission |= S_IEXEC;
4649 else
4651 #if 0 /* no way of knowing the filename */
4652 char * p = strrchr (name, '.');
4653 if (p != NULL &&
4654 (xstrcasecmp (p, ".exe") == 0 ||
4655 xstrcasecmp (p, ".com") == 0 ||
4656 xstrcasecmp (p, ".bat") == 0 ||
4657 xstrcasecmp (p, ".cmd") == 0))
4658 permission |= S_IEXEC;
4659 #endif
4662 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
4664 return 0;
4667 /* A version of 'utime' which handles directories as well as
4668 files. */
4671 utime (const char *name, struct utimbuf *times)
4673 struct utimbuf deftime;
4674 HANDLE fh;
4675 FILETIME mtime;
4676 FILETIME atime;
4678 if (times == NULL)
4680 deftime.modtime = deftime.actime = time (NULL);
4681 times = &deftime;
4684 if (w32_unicode_filenames)
4686 wchar_t name_utf16[MAX_PATH];
4688 if (filename_to_utf16 (name, name_utf16) != 0)
4689 return -1; /* errno set by filename_to_utf16 */
4691 /* Need write access to set times. */
4692 fh = CreateFileW (name_utf16, FILE_WRITE_ATTRIBUTES,
4693 /* If NAME specifies a directory, FILE_SHARE_DELETE
4694 allows other processes to delete files inside it,
4695 while we have the directory open. */
4696 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
4697 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
4699 else
4701 char name_ansi[MAX_PATH];
4703 if (filename_to_ansi (name, name_ansi) != 0)
4704 return -1; /* errno set by filename_to_ansi */
4706 fh = CreateFileA (name_ansi, FILE_WRITE_ATTRIBUTES,
4707 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
4708 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
4710 if (fh != INVALID_HANDLE_VALUE)
4712 convert_from_time_t (times->actime, &atime);
4713 convert_from_time_t (times->modtime, &mtime);
4714 if (!SetFileTime (fh, NULL, &atime, &mtime))
4716 CloseHandle (fh);
4717 errno = EACCES;
4718 return -1;
4720 CloseHandle (fh);
4722 else
4724 DWORD err = GetLastError ();
4726 switch (err)
4728 case ERROR_FILE_NOT_FOUND:
4729 case ERROR_PATH_NOT_FOUND:
4730 case ERROR_INVALID_DRIVE:
4731 case ERROR_BAD_NETPATH:
4732 case ERROR_DEV_NOT_EXIST:
4733 /* ERROR_INVALID_NAME is the error CreateFile sets when the
4734 file name includes ?s, i.e. translation to ANSI failed. */
4735 case ERROR_INVALID_NAME:
4736 errno = ENOENT;
4737 break;
4738 case ERROR_TOO_MANY_OPEN_FILES:
4739 errno = ENFILE;
4740 break;
4741 case ERROR_ACCESS_DENIED:
4742 case ERROR_SHARING_VIOLATION:
4743 errno = EACCES;
4744 break;
4745 default:
4746 errno = EINVAL;
4747 break;
4749 return -1;
4751 return 0;
4755 /* Symlink-related functions. */
4756 #ifndef SYMBOLIC_LINK_FLAG_DIRECTORY
4757 #define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1
4758 #endif
4761 symlink (char const *filename, char const *linkname)
4763 char linkfn[MAX_PATH], *tgtfn;
4764 DWORD flags = 0;
4765 int dir_access, filename_ends_in_slash;
4766 int dbcs_p;
4768 /* Diagnostics follows Posix as much as possible. */
4769 if (filename == NULL || linkname == NULL)
4771 errno = EFAULT;
4772 return -1;
4774 if (!*filename)
4776 errno = ENOENT;
4777 return -1;
4779 if (strlen (filename) > MAX_PATH || strlen (linkname) > MAX_PATH)
4781 errno = ENAMETOOLONG;
4782 return -1;
4785 strcpy (linkfn, map_w32_filename (linkname, NULL));
4786 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) == 0)
4788 errno = EPERM;
4789 return -1;
4792 dbcs_p = max_filename_mbslen () > 1;
4794 /* Note: since empty FILENAME was already rejected, we can safely
4795 refer to FILENAME[1]. */
4796 if (!(IS_DIRECTORY_SEP (filename[0]) || IS_DEVICE_SEP (filename[1])))
4798 /* Non-absolute FILENAME is understood as being relative to
4799 LINKNAME's directory. We need to prepend that directory to
4800 FILENAME to get correct results from faccessat below, since
4801 otherwise it will interpret FILENAME relative to the
4802 directory where the Emacs process runs. Note that
4803 make-symbolic-link always makes sure LINKNAME is a fully
4804 expanded file name. */
4805 char tem[MAX_PATH];
4806 char *p = linkfn + strlen (linkfn);
4808 if (!dbcs_p)
4810 while (p > linkfn && !IS_ANY_SEP (p[-1]))
4811 p--;
4813 else
4815 char *p1 = CharPrevExA (file_name_codepage, linkfn, p, 0);
4817 while (p > linkfn && !IS_ANY_SEP (*p1))
4819 p = p1;
4820 p1 = CharPrevExA (file_name_codepage, linkfn, p1, 0);
4823 if (p > linkfn)
4824 strncpy (tem, linkfn, p - linkfn);
4825 tem[p - linkfn] = '\0';
4826 strcat (tem, filename);
4827 dir_access = faccessat (AT_FDCWD, tem, D_OK, AT_EACCESS);
4829 else
4830 dir_access = faccessat (AT_FDCWD, filename, D_OK, AT_EACCESS);
4832 /* Since Windows distinguishes between symlinks to directories and
4833 to files, we provide a kludgy feature: if FILENAME doesn't
4834 exist, but ends in a slash, we create a symlink to directory. If
4835 FILENAME exists and is a directory, we always create a symlink to
4836 directory. */
4837 if (!dbcs_p)
4838 filename_ends_in_slash = IS_DIRECTORY_SEP (filename[strlen (filename) - 1]);
4839 else
4841 const char *end = filename + strlen (filename);
4842 const char *n = CharPrevExA (file_name_codepage, filename, end, 0);
4844 filename_ends_in_slash = IS_DIRECTORY_SEP (*n);
4846 if (dir_access == 0 || filename_ends_in_slash)
4847 flags = SYMBOLIC_LINK_FLAG_DIRECTORY;
4849 tgtfn = (char *)map_w32_filename (filename, NULL);
4850 if (filename_ends_in_slash)
4851 tgtfn[strlen (tgtfn) - 1] = '\0';
4853 errno = 0;
4854 if (!create_symbolic_link (linkfn, tgtfn, flags))
4856 /* ENOSYS is set by create_symbolic_link, when it detects that
4857 the OS doesn't support the CreateSymbolicLink API. */
4858 if (errno != ENOSYS)
4860 DWORD w32err = GetLastError ();
4862 switch (w32err)
4864 /* ERROR_SUCCESS is sometimes returned when LINKFN and
4865 TGTFN point to the same file name, go figure. */
4866 case ERROR_SUCCESS:
4867 case ERROR_FILE_EXISTS:
4868 errno = EEXIST;
4869 break;
4870 case ERROR_ACCESS_DENIED:
4871 errno = EACCES;
4872 break;
4873 case ERROR_FILE_NOT_FOUND:
4874 case ERROR_PATH_NOT_FOUND:
4875 case ERROR_BAD_NETPATH:
4876 case ERROR_INVALID_REPARSE_DATA:
4877 errno = ENOENT;
4878 break;
4879 case ERROR_DIRECTORY:
4880 errno = EISDIR;
4881 break;
4882 case ERROR_PRIVILEGE_NOT_HELD:
4883 case ERROR_NOT_ALL_ASSIGNED:
4884 errno = EPERM;
4885 break;
4886 case ERROR_DISK_FULL:
4887 errno = ENOSPC;
4888 break;
4889 default:
4890 errno = EINVAL;
4891 break;
4894 return -1;
4896 return 0;
4899 /* A quick inexpensive test of whether FILENAME identifies a file that
4900 is a symlink. Returns non-zero if it is, zero otherwise. FILENAME
4901 must already be in the normalized form returned by
4902 map_w32_filename.
4904 Note: for repeated operations on many files, it is best to test
4905 whether the underlying volume actually supports symlinks, by
4906 testing the FILE_SUPPORTS_REPARSE_POINTS bit in volume's flags, and
4907 avoid the call to this function if it doesn't. That's because the
4908 call to GetFileAttributes takes a non-negligible time, especially
4909 on non-local or removable filesystems. See stat_worker for an
4910 example of how to do that. */
4911 static int
4912 is_symlink (const char *filename)
4914 DWORD attrs;
4915 WIN32_FIND_DATA wfd;
4916 HANDLE fh;
4918 attrs = GetFileAttributes (filename);
4919 if (attrs == -1)
4921 DWORD w32err = GetLastError ();
4923 switch (w32err)
4925 case ERROR_BAD_NETPATH: /* network share, can't be a symlink */
4926 break;
4927 case ERROR_ACCESS_DENIED:
4928 errno = EACCES;
4929 break;
4930 case ERROR_FILE_NOT_FOUND:
4931 case ERROR_PATH_NOT_FOUND:
4932 default:
4933 errno = ENOENT;
4934 break;
4936 return 0;
4938 if ((attrs & FILE_ATTRIBUTE_REPARSE_POINT) == 0)
4939 return 0;
4940 logon_network_drive (filename);
4941 fh = FindFirstFile (filename, &wfd);
4942 if (fh == INVALID_HANDLE_VALUE)
4943 return 0;
4944 FindClose (fh);
4945 return (wfd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0
4946 && (wfd.dwReserved0 & IO_REPARSE_TAG_SYMLINK) == IO_REPARSE_TAG_SYMLINK;
4949 /* If NAME identifies a symbolic link, copy into BUF the file name of
4950 the symlink's target. Copy at most BUF_SIZE bytes, and do NOT
4951 null-terminate the target name, even if it fits. Return the number
4952 of bytes copied, or -1 if NAME is not a symlink or any error was
4953 encountered while resolving it. The file name copied into BUF is
4954 encoded in the current ANSI codepage. */
4955 ssize_t
4956 readlink (const char *name, char *buf, size_t buf_size)
4958 const char *path;
4959 TOKEN_PRIVILEGES privs;
4960 int restore_privs = 0;
4961 HANDLE sh;
4962 ssize_t retval;
4964 if (name == NULL)
4966 errno = EFAULT;
4967 return -1;
4969 if (!*name)
4971 errno = ENOENT;
4972 return -1;
4975 path = map_w32_filename (name, NULL);
4977 if (strlen (path) > MAX_PATH)
4979 errno = ENAMETOOLONG;
4980 return -1;
4983 errno = 0;
4984 if (is_windows_9x () == TRUE
4985 || (volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) == 0
4986 || !is_symlink (path))
4988 if (!errno)
4989 errno = EINVAL; /* not a symlink */
4990 return -1;
4993 /* Done with simple tests, now we're in for some _real_ work. */
4994 if (enable_privilege (SE_BACKUP_NAME, TRUE, &privs))
4995 restore_privs = 1;
4996 /* Implementation note: From here and onward, don't return early,
4997 since that will fail to restore the original set of privileges of
4998 the calling thread. */
5000 retval = -1; /* not too optimistic, are we? */
5002 /* Note: In the next call to CreateFile, we use zero as the 2nd
5003 argument because, when the symlink is a hidden/system file,
5004 e.g. 'C:\Users\All Users', GENERIC_READ fails with
5005 ERROR_ACCESS_DENIED. Zero seems to work just fine, both for file
5006 and directory symlinks. */
5007 sh = CreateFile (path, 0, 0, NULL, OPEN_EXISTING,
5008 FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
5009 NULL);
5010 if (sh != INVALID_HANDLE_VALUE)
5012 BYTE reparse_buf[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
5013 REPARSE_DATA_BUFFER *reparse_data = (REPARSE_DATA_BUFFER *)&reparse_buf[0];
5014 DWORD retbytes;
5016 if (!DeviceIoControl (sh, FSCTL_GET_REPARSE_POINT, NULL, 0,
5017 reparse_buf, MAXIMUM_REPARSE_DATA_BUFFER_SIZE,
5018 &retbytes, NULL))
5019 errno = EIO;
5020 else if (reparse_data->ReparseTag != IO_REPARSE_TAG_SYMLINK)
5021 errno = EINVAL;
5022 else
5024 /* Copy the link target name, in wide characters, from
5025 reparse_data, then convert it to multibyte encoding in
5026 the current locale's codepage. */
5027 WCHAR *lwname;
5028 BYTE lname[MAX_PATH];
5029 USHORT lname_len;
5030 USHORT lwname_len =
5031 reparse_data->SymbolicLinkReparseBuffer.PrintNameLength;
5032 WCHAR *lwname_src =
5033 reparse_data->SymbolicLinkReparseBuffer.PathBuffer
5034 + reparse_data->SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(WCHAR);
5035 /* This updates file_name_codepage which we need below. */
5036 int dbcs_p = max_filename_mbslen () > 1;
5038 /* According to MSDN, PrintNameLength does not include the
5039 terminating null character. */
5040 lwname = alloca ((lwname_len + 1) * sizeof(WCHAR));
5041 memcpy (lwname, lwname_src, lwname_len);
5042 lwname[lwname_len/sizeof(WCHAR)] = 0; /* null-terminate */
5044 lname_len = WideCharToMultiByte (file_name_codepage, 0, lwname, -1,
5045 lname, MAX_PATH, NULL, NULL);
5046 if (!lname_len)
5048 /* WideCharToMultiByte failed. */
5049 DWORD w32err1 = GetLastError ();
5051 switch (w32err1)
5053 case ERROR_INSUFFICIENT_BUFFER:
5054 errno = ENAMETOOLONG;
5055 break;
5056 case ERROR_INVALID_PARAMETER:
5057 errno = EFAULT;
5058 break;
5059 case ERROR_NO_UNICODE_TRANSLATION:
5060 errno = ENOENT;
5061 break;
5062 default:
5063 errno = EINVAL;
5064 break;
5067 else
5069 size_t size_to_copy = buf_size;
5070 BYTE *p = lname, *p2;
5071 BYTE *pend = p + lname_len;
5073 /* Normalize like dostounix_filename does, but we don't
5074 want to assume that lname is null-terminated. */
5075 if (dbcs_p)
5076 p2 = CharNextExA (file_name_codepage, p, 0);
5077 else
5078 p2 = p + 1;
5079 if (*p && *p2 == ':' && *p >= 'A' && *p <= 'Z')
5081 *p += 'a' - 'A';
5082 p += 2;
5084 while (p <= pend)
5086 if (*p == '\\')
5087 *p = '/';
5088 if (dbcs_p)
5090 p = CharNextExA (file_name_codepage, p, 0);
5091 /* CharNextExA doesn't advance at null character. */
5092 if (!*p)
5093 break;
5095 else
5096 ++p;
5098 /* Testing for null-terminated LNAME is paranoia:
5099 WideCharToMultiByte should always return a
5100 null-terminated string when its 4th argument is -1
5101 and its 3rd argument is null-terminated (which they
5102 are, see above). */
5103 if (lname[lname_len - 1] == '\0')
5104 lname_len--;
5105 if (lname_len <= buf_size)
5106 size_to_copy = lname_len;
5107 strncpy (buf, lname, size_to_copy);
5108 /* Success! */
5109 retval = size_to_copy;
5112 CloseHandle (sh);
5114 else
5116 /* CreateFile failed. */
5117 DWORD w32err2 = GetLastError ();
5119 switch (w32err2)
5121 case ERROR_FILE_NOT_FOUND:
5122 case ERROR_PATH_NOT_FOUND:
5123 errno = ENOENT;
5124 break;
5125 case ERROR_ACCESS_DENIED:
5126 case ERROR_TOO_MANY_OPEN_FILES:
5127 errno = EACCES;
5128 break;
5129 default:
5130 errno = EPERM;
5131 break;
5134 if (restore_privs)
5136 restore_privilege (&privs);
5137 revert_to_self ();
5140 return retval;
5143 ssize_t
5144 readlinkat (int fd, char const *name, char *buffer,
5145 size_t buffer_size)
5147 /* Rely on a hack: an open directory is modeled as file descriptor 0,
5148 as in fstatat. FIXME: Add proper support for readlinkat. */
5149 char fullname[MAX_PATH];
5151 if (fd != AT_FDCWD)
5153 if (_snprintf (fullname, sizeof fullname, "%s/%s", dir_pathname, name)
5154 < 0)
5156 errno = ENAMETOOLONG;
5157 return -1;
5159 name = fullname;
5162 return readlink (name, buffer, buffer_size);
5165 /* If FILE is a symlink, return its target (stored in a static
5166 buffer); otherwise return FILE.
5168 This function repeatedly resolves symlinks in the last component of
5169 a chain of symlink file names, as in foo -> bar -> baz -> ...,
5170 until it arrives at a file whose last component is not a symlink,
5171 or some error occurs. It returns the target of the last
5172 successfully resolved symlink in the chain. If it succeeds to
5173 resolve even a single symlink, the value returned is an absolute
5174 file name with backslashes (result of GetFullPathName). By
5175 contrast, if the original FILE is returned, it is unaltered.
5177 Note: This function can set errno even if it succeeds.
5179 Implementation note: we only resolve the last portion ("basename")
5180 of the argument FILE and of each following file in the chain,
5181 disregarding any possible symlinks in its leading directories.
5182 This is because Windows system calls and library functions
5183 transparently resolve symlinks in leading directories and return
5184 correct information, as long as the basename is not a symlink. */
5185 static char *
5186 chase_symlinks (const char *file)
5188 static char target[MAX_PATH];
5189 char link[MAX_PATH];
5190 ssize_t res, link_len;
5191 int loop_count = 0;
5192 int dbcs_p;
5194 if (is_windows_9x () == TRUE || !is_symlink (file))
5195 return (char *)file;
5197 if ((link_len = GetFullPathName (file, MAX_PATH, link, NULL)) == 0)
5198 return (char *)file;
5200 dbcs_p = max_filename_mbslen () > 1;
5201 target[0] = '\0';
5202 do {
5204 /* Remove trailing slashes, as we want to resolve the last
5205 non-trivial part of the link name. */
5206 if (!dbcs_p)
5208 while (link_len > 3 && IS_DIRECTORY_SEP (link[link_len-1]))
5209 link[link_len--] = '\0';
5211 else if (link_len > 3)
5213 char *n = CharPrevExA (file_name_codepage, link, link + link_len, 0);
5215 while (n >= link + 2 && IS_DIRECTORY_SEP (*n))
5217 n[1] = '\0';
5218 n = CharPrevExA (file_name_codepage, link, n, 0);
5222 res = readlink (link, target, MAX_PATH);
5223 if (res > 0)
5225 target[res] = '\0';
5226 if (!(IS_DEVICE_SEP (target[1])
5227 || (IS_DIRECTORY_SEP (target[0]) && IS_DIRECTORY_SEP (target[1]))))
5229 /* Target is relative. Append it to the directory part of
5230 the symlink, then copy the result back to target. */
5231 char *p = link + link_len;
5233 if (!dbcs_p)
5235 while (p > link && !IS_ANY_SEP (p[-1]))
5236 p--;
5238 else
5240 char *p1 = CharPrevExA (file_name_codepage, link, p, 0);
5242 while (p > link && !IS_ANY_SEP (*p1))
5244 p = p1;
5245 p1 = CharPrevExA (file_name_codepage, link, p1, 0);
5248 strcpy (p, target);
5249 strcpy (target, link);
5251 /* Resolve any "." and ".." to get a fully-qualified file name
5252 in link[] again. */
5253 link_len = GetFullPathName (target, MAX_PATH, link, NULL);
5255 } while (res > 0 && link_len > 0 && ++loop_count <= 100);
5257 if (loop_count > 100)
5258 errno = ELOOP;
5260 if (target[0] == '\0') /* not a single call to readlink succeeded */
5261 return (char *)file;
5262 return target;
5266 /* Posix ACL emulation. */
5269 acl_valid (acl_t acl)
5271 return is_valid_security_descriptor ((PSECURITY_DESCRIPTOR)acl) ? 0 : -1;
5274 char *
5275 acl_to_text (acl_t acl, ssize_t *size)
5277 LPTSTR str_acl;
5278 SECURITY_INFORMATION flags =
5279 OWNER_SECURITY_INFORMATION |
5280 GROUP_SECURITY_INFORMATION |
5281 DACL_SECURITY_INFORMATION;
5282 char *retval = NULL;
5283 ULONG local_size;
5284 int e = errno;
5286 errno = 0;
5288 if (convert_sd_to_sddl ((PSECURITY_DESCRIPTOR)acl, SDDL_REVISION_1, flags, &str_acl, &local_size))
5290 errno = e;
5291 /* We don't want to mix heaps, so we duplicate the string in our
5292 heap and free the one allocated by the API. */
5293 retval = xstrdup (str_acl);
5294 if (size)
5295 *size = local_size;
5296 LocalFree (str_acl);
5298 else if (errno != ENOTSUP)
5299 errno = EINVAL;
5301 return retval;
5304 acl_t
5305 acl_from_text (const char *acl_str)
5307 PSECURITY_DESCRIPTOR psd, retval = NULL;
5308 ULONG sd_size;
5309 int e = errno;
5311 errno = 0;
5313 if (convert_sddl_to_sd (acl_str, SDDL_REVISION_1, &psd, &sd_size))
5315 errno = e;
5316 retval = xmalloc (sd_size);
5317 memcpy (retval, psd, sd_size);
5318 LocalFree (psd);
5320 else if (errno != ENOTSUP)
5321 errno = EINVAL;
5323 return retval;
5327 acl_free (void *ptr)
5329 xfree (ptr);
5330 return 0;
5333 acl_t
5334 acl_get_file (const char *fname, acl_type_t type)
5336 PSECURITY_DESCRIPTOR psd = NULL;
5337 const char *filename;
5339 if (type == ACL_TYPE_ACCESS)
5341 DWORD sd_len, err;
5342 SECURITY_INFORMATION si =
5343 OWNER_SECURITY_INFORMATION |
5344 GROUP_SECURITY_INFORMATION |
5345 DACL_SECURITY_INFORMATION ;
5346 int e = errno;
5348 filename = map_w32_filename (fname, NULL);
5349 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
5350 fname = chase_symlinks (filename);
5351 else
5352 fname = filename;
5354 errno = 0;
5355 if (!get_file_security (fname, si, psd, 0, &sd_len)
5356 && errno != ENOTSUP)
5358 err = GetLastError ();
5359 if (err == ERROR_INSUFFICIENT_BUFFER)
5361 psd = xmalloc (sd_len);
5362 if (!get_file_security (fname, si, psd, sd_len, &sd_len))
5364 xfree (psd);
5365 errno = EIO;
5366 psd = NULL;
5369 else if (err == ERROR_FILE_NOT_FOUND
5370 || err == ERROR_PATH_NOT_FOUND)
5371 errno = ENOENT;
5372 else
5373 errno = EIO;
5375 else if (!errno)
5376 errno = e;
5378 else if (type != ACL_TYPE_DEFAULT)
5379 errno = EINVAL;
5381 return psd;
5385 acl_set_file (const char *fname, acl_type_t type, acl_t acl)
5387 TOKEN_PRIVILEGES old1, old2;
5388 DWORD err;
5389 int st = 0, retval = -1;
5390 SECURITY_INFORMATION flags = 0;
5391 PSID psid;
5392 PACL pacl;
5393 BOOL dflt;
5394 BOOL dacl_present;
5395 int e;
5396 const char *filename;
5398 if (acl_valid (acl) != 0
5399 || (type != ACL_TYPE_DEFAULT && type != ACL_TYPE_ACCESS))
5401 errno = EINVAL;
5402 return -1;
5405 if (type == ACL_TYPE_DEFAULT)
5407 errno = ENOSYS;
5408 return -1;
5411 filename = map_w32_filename (fname, NULL);
5412 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
5413 fname = chase_symlinks (filename);
5414 else
5415 fname = filename;
5417 if (get_security_descriptor_owner ((PSECURITY_DESCRIPTOR)acl, &psid, &dflt)
5418 && psid)
5419 flags |= OWNER_SECURITY_INFORMATION;
5420 if (get_security_descriptor_group ((PSECURITY_DESCRIPTOR)acl, &psid, &dflt)
5421 && psid)
5422 flags |= GROUP_SECURITY_INFORMATION;
5423 if (get_security_descriptor_dacl ((PSECURITY_DESCRIPTOR)acl, &dacl_present,
5424 &pacl, &dflt)
5425 && dacl_present)
5426 flags |= DACL_SECURITY_INFORMATION;
5427 if (!flags)
5428 return 0;
5430 /* According to KB-245153, setting the owner will succeed if either:
5431 (1) the caller is the user who will be the new owner, and has the
5432 SE_TAKE_OWNERSHIP privilege, or
5433 (2) the caller has the SE_RESTORE privilege, in which case she can
5434 set any valid user or group as the owner
5436 We request below both SE_TAKE_OWNERSHIP and SE_RESTORE
5437 privileges, and disregard any failures in obtaining them. If
5438 these privileges cannot be obtained, and do not already exist in
5439 the calling thread's security token, this function could fail
5440 with EPERM. */
5441 if (enable_privilege (SE_TAKE_OWNERSHIP_NAME, TRUE, &old1))
5442 st++;
5443 if (enable_privilege (SE_RESTORE_NAME, TRUE, &old2))
5444 st++;
5446 e = errno;
5447 errno = 0;
5448 if (!set_file_security ((char *)fname, flags, (PSECURITY_DESCRIPTOR)acl))
5450 err = GetLastError ();
5452 if (errno == ENOTSUP)
5454 else if (err == ERROR_INVALID_OWNER
5455 || err == ERROR_NOT_ALL_ASSIGNED
5456 || err == ERROR_ACCESS_DENIED)
5458 /* Maybe the requested ACL and the one the file already has
5459 are identical, in which case we can silently ignore the
5460 failure. (And no, Windows doesn't.) */
5461 acl_t current_acl = acl_get_file (fname, ACL_TYPE_ACCESS);
5463 errno = EPERM;
5464 if (current_acl)
5466 char *acl_from = acl_to_text (current_acl, NULL);
5467 char *acl_to = acl_to_text (acl, NULL);
5469 if (acl_from && acl_to && xstrcasecmp (acl_from, acl_to) == 0)
5471 retval = 0;
5472 errno = e;
5474 if (acl_from)
5475 acl_free (acl_from);
5476 if (acl_to)
5477 acl_free (acl_to);
5478 acl_free (current_acl);
5481 else if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND)
5482 errno = ENOENT;
5483 else
5484 errno = EACCES;
5486 else
5488 retval = 0;
5489 errno = e;
5492 if (st)
5494 if (st >= 2)
5495 restore_privilege (&old2);
5496 restore_privilege (&old1);
5497 revert_to_self ();
5500 return retval;
5504 /* MS-Windows version of careadlinkat (cf. ../lib/careadlinkat.c). We
5505 have a fixed max size for file names, so we don't need the kind of
5506 alloc/malloc/realloc dance the gnulib version does. We also don't
5507 support FD-relative symlinks. */
5508 char *
5509 careadlinkat (int fd, char const *filename,
5510 char *buffer, size_t buffer_size,
5511 struct allocator const *alloc,
5512 ssize_t (*preadlinkat) (int, char const *, char *, size_t))
5514 char linkname[MAX_PATH];
5515 ssize_t link_size;
5517 link_size = preadlinkat (fd, filename, linkname, sizeof(linkname));
5519 if (link_size > 0)
5521 char *retval = buffer;
5523 linkname[link_size++] = '\0';
5524 if (link_size > buffer_size)
5525 retval = (char *)(alloc ? alloc->allocate : xmalloc) (link_size);
5526 if (retval)
5527 memcpy (retval, linkname, link_size);
5529 return retval;
5531 return NULL;
5535 /* Support for browsing other processes and their attributes. See
5536 process.c for the Lisp bindings. */
5538 /* Helper wrapper functions. */
5540 static HANDLE WINAPI
5541 create_toolhelp32_snapshot (DWORD Flags, DWORD Ignored)
5543 static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot = NULL;
5545 if (g_b_init_create_toolhelp32_snapshot == 0)
5547 g_b_init_create_toolhelp32_snapshot = 1;
5548 s_pfn_Create_Toolhelp32_Snapshot = (CreateToolhelp32Snapshot_Proc)
5549 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5550 "CreateToolhelp32Snapshot");
5552 if (s_pfn_Create_Toolhelp32_Snapshot == NULL)
5554 return INVALID_HANDLE_VALUE;
5556 return (s_pfn_Create_Toolhelp32_Snapshot (Flags, Ignored));
5559 static BOOL WINAPI
5560 process32_first (HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
5562 static Process32First_Proc s_pfn_Process32_First = NULL;
5564 if (g_b_init_process32_first == 0)
5566 g_b_init_process32_first = 1;
5567 s_pfn_Process32_First = (Process32First_Proc)
5568 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5569 "Process32First");
5571 if (s_pfn_Process32_First == NULL)
5573 return FALSE;
5575 return (s_pfn_Process32_First (hSnapshot, lppe));
5578 static BOOL WINAPI
5579 process32_next (HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
5581 static Process32Next_Proc s_pfn_Process32_Next = NULL;
5583 if (g_b_init_process32_next == 0)
5585 g_b_init_process32_next = 1;
5586 s_pfn_Process32_Next = (Process32Next_Proc)
5587 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5588 "Process32Next");
5590 if (s_pfn_Process32_Next == NULL)
5592 return FALSE;
5594 return (s_pfn_Process32_Next (hSnapshot, lppe));
5597 static BOOL WINAPI
5598 open_thread_token (HANDLE ThreadHandle,
5599 DWORD DesiredAccess,
5600 BOOL OpenAsSelf,
5601 PHANDLE TokenHandle)
5603 static OpenThreadToken_Proc s_pfn_Open_Thread_Token = NULL;
5604 HMODULE hm_advapi32 = NULL;
5605 if (is_windows_9x () == TRUE)
5607 SetLastError (ERROR_NOT_SUPPORTED);
5608 return FALSE;
5610 if (g_b_init_open_thread_token == 0)
5612 g_b_init_open_thread_token = 1;
5613 hm_advapi32 = LoadLibrary ("Advapi32.dll");
5614 s_pfn_Open_Thread_Token =
5615 (OpenThreadToken_Proc) GetProcAddress (hm_advapi32, "OpenThreadToken");
5617 if (s_pfn_Open_Thread_Token == NULL)
5619 SetLastError (ERROR_NOT_SUPPORTED);
5620 return FALSE;
5622 return (
5623 s_pfn_Open_Thread_Token (
5624 ThreadHandle,
5625 DesiredAccess,
5626 OpenAsSelf,
5627 TokenHandle)
5631 static BOOL WINAPI
5632 impersonate_self (SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
5634 static ImpersonateSelf_Proc s_pfn_Impersonate_Self = NULL;
5635 HMODULE hm_advapi32 = NULL;
5636 if (is_windows_9x () == TRUE)
5638 return FALSE;
5640 if (g_b_init_impersonate_self == 0)
5642 g_b_init_impersonate_self = 1;
5643 hm_advapi32 = LoadLibrary ("Advapi32.dll");
5644 s_pfn_Impersonate_Self =
5645 (ImpersonateSelf_Proc) GetProcAddress (hm_advapi32, "ImpersonateSelf");
5647 if (s_pfn_Impersonate_Self == NULL)
5649 return FALSE;
5651 return s_pfn_Impersonate_Self (ImpersonationLevel);
5654 static BOOL WINAPI
5655 revert_to_self (void)
5657 static RevertToSelf_Proc s_pfn_Revert_To_Self = NULL;
5658 HMODULE hm_advapi32 = NULL;
5659 if (is_windows_9x () == TRUE)
5661 return FALSE;
5663 if (g_b_init_revert_to_self == 0)
5665 g_b_init_revert_to_self = 1;
5666 hm_advapi32 = LoadLibrary ("Advapi32.dll");
5667 s_pfn_Revert_To_Self =
5668 (RevertToSelf_Proc) GetProcAddress (hm_advapi32, "RevertToSelf");
5670 if (s_pfn_Revert_To_Self == NULL)
5672 return FALSE;
5674 return s_pfn_Revert_To_Self ();
5677 static BOOL WINAPI
5678 get_process_memory_info (HANDLE h_proc,
5679 PPROCESS_MEMORY_COUNTERS mem_counters,
5680 DWORD bufsize)
5682 static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info = NULL;
5683 HMODULE hm_psapi = NULL;
5684 if (is_windows_9x () == TRUE)
5686 return FALSE;
5688 if (g_b_init_get_process_memory_info == 0)
5690 g_b_init_get_process_memory_info = 1;
5691 hm_psapi = LoadLibrary ("Psapi.dll");
5692 if (hm_psapi)
5693 s_pfn_Get_Process_Memory_Info = (GetProcessMemoryInfo_Proc)
5694 GetProcAddress (hm_psapi, "GetProcessMemoryInfo");
5696 if (s_pfn_Get_Process_Memory_Info == NULL)
5698 return FALSE;
5700 return s_pfn_Get_Process_Memory_Info (h_proc, mem_counters, bufsize);
5703 static BOOL WINAPI
5704 get_process_working_set_size (HANDLE h_proc,
5705 PSIZE_T minrss,
5706 PSIZE_T maxrss)
5708 static GetProcessWorkingSetSize_Proc
5709 s_pfn_Get_Process_Working_Set_Size = NULL;
5711 if (is_windows_9x () == TRUE)
5713 return FALSE;
5715 if (g_b_init_get_process_working_set_size == 0)
5717 g_b_init_get_process_working_set_size = 1;
5718 s_pfn_Get_Process_Working_Set_Size = (GetProcessWorkingSetSize_Proc)
5719 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5720 "GetProcessWorkingSetSize");
5722 if (s_pfn_Get_Process_Working_Set_Size == NULL)
5724 return FALSE;
5726 return s_pfn_Get_Process_Working_Set_Size (h_proc, minrss, maxrss);
5729 static BOOL WINAPI
5730 global_memory_status (MEMORYSTATUS *buf)
5732 static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status = NULL;
5734 if (is_windows_9x () == TRUE)
5736 return FALSE;
5738 if (g_b_init_global_memory_status == 0)
5740 g_b_init_global_memory_status = 1;
5741 s_pfn_Global_Memory_Status = (GlobalMemoryStatus_Proc)
5742 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5743 "GlobalMemoryStatus");
5745 if (s_pfn_Global_Memory_Status == NULL)
5747 return FALSE;
5749 return s_pfn_Global_Memory_Status (buf);
5752 static BOOL WINAPI
5753 global_memory_status_ex (MEMORY_STATUS_EX *buf)
5755 static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex = NULL;
5757 if (is_windows_9x () == TRUE)
5759 return FALSE;
5761 if (g_b_init_global_memory_status_ex == 0)
5763 g_b_init_global_memory_status_ex = 1;
5764 s_pfn_Global_Memory_Status_Ex = (GlobalMemoryStatusEx_Proc)
5765 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5766 "GlobalMemoryStatusEx");
5768 if (s_pfn_Global_Memory_Status_Ex == NULL)
5770 return FALSE;
5772 return s_pfn_Global_Memory_Status_Ex (buf);
5775 Lisp_Object
5776 list_system_processes (void)
5778 struct gcpro gcpro1;
5779 Lisp_Object proclist = Qnil;
5780 HANDLE h_snapshot;
5782 h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
5784 if (h_snapshot != INVALID_HANDLE_VALUE)
5786 PROCESSENTRY32 proc_entry;
5787 DWORD proc_id;
5788 BOOL res;
5790 GCPRO1 (proclist);
5792 proc_entry.dwSize = sizeof (PROCESSENTRY32);
5793 for (res = process32_first (h_snapshot, &proc_entry); res;
5794 res = process32_next (h_snapshot, &proc_entry))
5796 proc_id = proc_entry.th32ProcessID;
5797 proclist = Fcons (make_fixnum_or_float (proc_id), proclist);
5800 CloseHandle (h_snapshot);
5801 UNGCPRO;
5802 proclist = Fnreverse (proclist);
5805 return proclist;
5808 static int
5809 enable_privilege (LPCTSTR priv_name, BOOL enable_p, TOKEN_PRIVILEGES *old_priv)
5811 TOKEN_PRIVILEGES priv;
5812 DWORD priv_size = sizeof (priv);
5813 DWORD opriv_size = sizeof (*old_priv);
5814 HANDLE h_token = NULL;
5815 HANDLE h_thread = GetCurrentThread ();
5816 int ret_val = 0;
5817 BOOL res;
5819 res = open_thread_token (h_thread,
5820 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
5821 FALSE, &h_token);
5822 if (!res && GetLastError () == ERROR_NO_TOKEN)
5824 if (impersonate_self (SecurityImpersonation))
5825 res = open_thread_token (h_thread,
5826 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
5827 FALSE, &h_token);
5829 if (res)
5831 priv.PrivilegeCount = 1;
5832 priv.Privileges[0].Attributes = enable_p ? SE_PRIVILEGE_ENABLED : 0;
5833 LookupPrivilegeValue (NULL, priv_name, &priv.Privileges[0].Luid);
5834 if (AdjustTokenPrivileges (h_token, FALSE, &priv, priv_size,
5835 old_priv, &opriv_size)
5836 && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
5837 ret_val = 1;
5839 if (h_token)
5840 CloseHandle (h_token);
5842 return ret_val;
5845 static int
5846 restore_privilege (TOKEN_PRIVILEGES *priv)
5848 DWORD priv_size = sizeof (*priv);
5849 HANDLE h_token = NULL;
5850 int ret_val = 0;
5852 if (open_thread_token (GetCurrentThread (),
5853 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
5854 FALSE, &h_token))
5856 if (AdjustTokenPrivileges (h_token, FALSE, priv, priv_size, NULL, NULL)
5857 && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
5858 ret_val = 1;
5860 if (h_token)
5861 CloseHandle (h_token);
5863 return ret_val;
5866 static Lisp_Object
5867 ltime (ULONGLONG time_100ns)
5869 ULONGLONG time_sec = time_100ns / 10000000;
5870 int subsec = time_100ns % 10000000;
5871 return list4i (time_sec >> 16, time_sec & 0xffff,
5872 subsec / 10, subsec % 10 * 100000);
5875 #define U64_TO_LISP_TIME(time) ltime (time)
5877 static int
5878 process_times (HANDLE h_proc, Lisp_Object *ctime, Lisp_Object *etime,
5879 Lisp_Object *stime, Lisp_Object *utime, Lisp_Object *ttime,
5880 double *pcpu)
5882 FILETIME ft_creation, ft_exit, ft_kernel, ft_user, ft_current;
5883 ULONGLONG tem1, tem2, tem3, tem;
5885 if (!h_proc
5886 || !get_process_times_fn
5887 || !(*get_process_times_fn) (h_proc, &ft_creation, &ft_exit,
5888 &ft_kernel, &ft_user))
5889 return 0;
5891 GetSystemTimeAsFileTime (&ft_current);
5893 FILETIME_TO_U64 (tem1, ft_kernel);
5894 *stime = U64_TO_LISP_TIME (tem1);
5896 FILETIME_TO_U64 (tem2, ft_user);
5897 *utime = U64_TO_LISP_TIME (tem2);
5899 tem3 = tem1 + tem2;
5900 *ttime = U64_TO_LISP_TIME (tem3);
5902 FILETIME_TO_U64 (tem, ft_creation);
5903 /* Process no 4 (System) returns zero creation time. */
5904 if (tem)
5905 tem -= utc_base;
5906 *ctime = U64_TO_LISP_TIME (tem);
5908 if (tem)
5910 FILETIME_TO_U64 (tem3, ft_current);
5911 tem = (tem3 - utc_base) - tem;
5913 *etime = U64_TO_LISP_TIME (tem);
5915 if (tem)
5917 *pcpu = 100.0 * (tem1 + tem2) / tem;
5918 if (*pcpu > 100)
5919 *pcpu = 100.0;
5921 else
5922 *pcpu = 0;
5924 return 1;
5927 Lisp_Object
5928 system_process_attributes (Lisp_Object pid)
5930 struct gcpro gcpro1, gcpro2, gcpro3;
5931 Lisp_Object attrs = Qnil;
5932 Lisp_Object cmd_str, decoded_cmd, tem;
5933 HANDLE h_snapshot, h_proc;
5934 DWORD proc_id;
5935 int found_proc = 0;
5936 char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
5937 DWORD ulength = sizeof (uname), dlength = sizeof (domain), needed;
5938 DWORD glength = sizeof (gname);
5939 HANDLE token = NULL;
5940 SID_NAME_USE user_type;
5941 unsigned char *buf = NULL;
5942 DWORD blen = 0;
5943 TOKEN_USER user_token;
5944 TOKEN_PRIMARY_GROUP group_token;
5945 unsigned euid;
5946 unsigned egid;
5947 PROCESS_MEMORY_COUNTERS mem;
5948 PROCESS_MEMORY_COUNTERS_EX mem_ex;
5949 SIZE_T minrss, maxrss;
5950 MEMORYSTATUS memst;
5951 MEMORY_STATUS_EX memstex;
5952 double totphys = 0.0;
5953 Lisp_Object ctime, stime, utime, etime, ttime;
5954 double pcpu;
5955 BOOL result = FALSE;
5957 CHECK_NUMBER_OR_FLOAT (pid);
5958 proc_id = FLOATP (pid) ? XFLOAT_DATA (pid) : XINT (pid);
5960 h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
5962 GCPRO3 (attrs, decoded_cmd, tem);
5964 if (h_snapshot != INVALID_HANDLE_VALUE)
5966 PROCESSENTRY32 pe;
5967 BOOL res;
5969 pe.dwSize = sizeof (PROCESSENTRY32);
5970 for (res = process32_first (h_snapshot, &pe); res;
5971 res = process32_next (h_snapshot, &pe))
5973 if (proc_id == pe.th32ProcessID)
5975 if (proc_id == 0)
5976 decoded_cmd = build_string ("Idle");
5977 else
5979 /* Decode the command name from locale-specific
5980 encoding. */
5981 cmd_str = build_unibyte_string (pe.szExeFile);
5983 decoded_cmd =
5984 code_convert_string_norecord (cmd_str,
5985 Vlocale_coding_system, 0);
5987 attrs = Fcons (Fcons (Qcomm, decoded_cmd), attrs);
5988 attrs = Fcons (Fcons (Qppid,
5989 make_fixnum_or_float (pe.th32ParentProcessID)),
5990 attrs);
5991 attrs = Fcons (Fcons (Qpri, make_number (pe.pcPriClassBase)),
5992 attrs);
5993 attrs = Fcons (Fcons (Qthcount,
5994 make_fixnum_or_float (pe.cntThreads)),
5995 attrs);
5996 found_proc = 1;
5997 break;
6001 CloseHandle (h_snapshot);
6004 if (!found_proc)
6006 UNGCPRO;
6007 return Qnil;
6010 h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
6011 FALSE, proc_id);
6012 /* If we were denied a handle to the process, try again after
6013 enabling the SeDebugPrivilege in our process. */
6014 if (!h_proc)
6016 TOKEN_PRIVILEGES priv_current;
6018 if (enable_privilege (SE_DEBUG_NAME, TRUE, &priv_current))
6020 h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
6021 FALSE, proc_id);
6022 restore_privilege (&priv_current);
6023 revert_to_self ();
6026 if (h_proc)
6028 result = open_process_token (h_proc, TOKEN_QUERY, &token);
6029 if (result)
6031 result = get_token_information (token, TokenUser, NULL, 0, &blen);
6032 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
6034 buf = xmalloc (blen);
6035 result = get_token_information (token, TokenUser,
6036 (LPVOID)buf, blen, &needed);
6037 if (result)
6039 memcpy (&user_token, buf, sizeof (user_token));
6040 if (!w32_cached_id (user_token.User.Sid, &euid, uname))
6042 euid = get_rid (user_token.User.Sid);
6043 result = lookup_account_sid (NULL, user_token.User.Sid,
6044 uname, &ulength,
6045 domain, &dlength,
6046 &user_type);
6047 if (result)
6048 w32_add_to_cache (user_token.User.Sid, euid, uname);
6049 else
6051 strcpy (uname, "unknown");
6052 result = TRUE;
6055 ulength = strlen (uname);
6059 if (result)
6061 /* Determine a reasonable euid and gid values. */
6062 if (xstrcasecmp ("administrator", uname) == 0)
6064 euid = 500; /* well-known Administrator uid */
6065 egid = 513; /* well-known None gid */
6067 else
6069 /* Get group id and name. */
6070 result = get_token_information (token, TokenPrimaryGroup,
6071 (LPVOID)buf, blen, &needed);
6072 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
6074 buf = xrealloc (buf, blen = needed);
6075 result = get_token_information (token, TokenPrimaryGroup,
6076 (LPVOID)buf, blen, &needed);
6078 if (result)
6080 memcpy (&group_token, buf, sizeof (group_token));
6081 if (!w32_cached_id (group_token.PrimaryGroup, &egid, gname))
6083 egid = get_rid (group_token.PrimaryGroup);
6084 dlength = sizeof (domain);
6085 result =
6086 lookup_account_sid (NULL, group_token.PrimaryGroup,
6087 gname, &glength, NULL, &dlength,
6088 &user_type);
6089 if (result)
6090 w32_add_to_cache (group_token.PrimaryGroup,
6091 egid, gname);
6092 else
6094 strcpy (gname, "None");
6095 result = TRUE;
6098 glength = strlen (gname);
6102 xfree (buf);
6104 if (!result)
6106 if (!is_windows_9x ())
6108 /* We couldn't open the process token, presumably because of
6109 insufficient access rights. Assume this process is run
6110 by the system. */
6111 strcpy (uname, "SYSTEM");
6112 strcpy (gname, "None");
6113 euid = 18; /* SYSTEM */
6114 egid = 513; /* None */
6115 glength = strlen (gname);
6116 ulength = strlen (uname);
6118 /* If we are running under Windows 9X, where security calls are
6119 not supported, we assume all processes are run by the current
6120 user. */
6121 else if (GetUserName (uname, &ulength))
6123 if (xstrcasecmp ("administrator", uname) == 0)
6124 euid = 0;
6125 else
6126 euid = 123;
6127 egid = euid;
6128 strcpy (gname, "None");
6129 glength = strlen (gname);
6130 ulength = strlen (uname);
6132 else
6134 euid = 123;
6135 egid = 123;
6136 strcpy (uname, "administrator");
6137 ulength = strlen (uname);
6138 strcpy (gname, "None");
6139 glength = strlen (gname);
6141 if (token)
6142 CloseHandle (token);
6145 attrs = Fcons (Fcons (Qeuid, make_fixnum_or_float (euid)), attrs);
6146 tem = make_unibyte_string (uname, ulength);
6147 attrs = Fcons (Fcons (Quser,
6148 code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
6149 attrs);
6150 attrs = Fcons (Fcons (Qegid, make_fixnum_or_float (egid)), attrs);
6151 tem = make_unibyte_string (gname, glength);
6152 attrs = Fcons (Fcons (Qgroup,
6153 code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
6154 attrs);
6156 if (global_memory_status_ex (&memstex))
6157 #if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
6158 totphys = memstex.ullTotalPhys / 1024.0;
6159 #else
6160 /* Visual Studio 6 cannot convert an unsigned __int64 type to
6161 double, so we need to do this for it... */
6163 DWORD tot_hi = memstex.ullTotalPhys >> 32;
6164 DWORD tot_md = (memstex.ullTotalPhys & 0x00000000ffffffff) >> 10;
6165 DWORD tot_lo = memstex.ullTotalPhys % 1024;
6167 totphys = tot_hi * 4194304.0 + tot_md + tot_lo / 1024.0;
6169 #endif /* __GNUC__ || _MSC_VER >= 1300 */
6170 else if (global_memory_status (&memst))
6171 totphys = memst.dwTotalPhys / 1024.0;
6173 if (h_proc
6174 && get_process_memory_info (h_proc, (PROCESS_MEMORY_COUNTERS *)&mem_ex,
6175 sizeof (mem_ex)))
6177 SIZE_T rss = mem_ex.WorkingSetSize / 1024;
6179 attrs = Fcons (Fcons (Qmajflt,
6180 make_fixnum_or_float (mem_ex.PageFaultCount)),
6181 attrs);
6182 attrs = Fcons (Fcons (Qvsize,
6183 make_fixnum_or_float (mem_ex.PrivateUsage / 1024)),
6184 attrs);
6185 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (rss)), attrs);
6186 if (totphys)
6187 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
6189 else if (h_proc
6190 && get_process_memory_info (h_proc, &mem, sizeof (mem)))
6192 SIZE_T rss = mem_ex.WorkingSetSize / 1024;
6194 attrs = Fcons (Fcons (Qmajflt,
6195 make_fixnum_or_float (mem.PageFaultCount)),
6196 attrs);
6197 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (rss)), attrs);
6198 if (totphys)
6199 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
6201 else if (h_proc
6202 && get_process_working_set_size (h_proc, &minrss, &maxrss))
6204 DWORD rss = maxrss / 1024;
6206 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (maxrss / 1024)), attrs);
6207 if (totphys)
6208 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
6211 if (process_times (h_proc, &ctime, &etime, &stime, &utime, &ttime, &pcpu))
6213 attrs = Fcons (Fcons (Qutime, utime), attrs);
6214 attrs = Fcons (Fcons (Qstime, stime), attrs);
6215 attrs = Fcons (Fcons (Qtime, ttime), attrs);
6216 attrs = Fcons (Fcons (Qstart, ctime), attrs);
6217 attrs = Fcons (Fcons (Qetime, etime), attrs);
6218 attrs = Fcons (Fcons (Qpcpu, make_float (pcpu)), attrs);
6221 /* FIXME: Retrieve command line by walking the PEB of the process. */
6223 if (h_proc)
6224 CloseHandle (h_proc);
6225 UNGCPRO;
6226 return attrs;
6230 /* Wrappers for winsock functions to map between our file descriptors
6231 and winsock's handles; also set h_errno for convenience.
6233 To allow Emacs to run on systems which don't have winsock support
6234 installed, we dynamically link to winsock on startup if present, and
6235 otherwise provide the minimum necessary functionality
6236 (eg. gethostname). */
6238 /* function pointers for relevant socket functions */
6239 int (PASCAL *pfn_WSAStartup) (WORD wVersionRequired, LPWSADATA lpWSAData);
6240 void (PASCAL *pfn_WSASetLastError) (int iError);
6241 int (PASCAL *pfn_WSAGetLastError) (void);
6242 int (PASCAL *pfn_WSAEventSelect) (SOCKET s, HANDLE hEventObject, long lNetworkEvents);
6243 HANDLE (PASCAL *pfn_WSACreateEvent) (void);
6244 int (PASCAL *pfn_WSACloseEvent) (HANDLE hEvent);
6245 int (PASCAL *pfn_socket) (int af, int type, int protocol);
6246 int (PASCAL *pfn_bind) (SOCKET s, const struct sockaddr *addr, int namelen);
6247 int (PASCAL *pfn_connect) (SOCKET s, const struct sockaddr *addr, int namelen);
6248 int (PASCAL *pfn_ioctlsocket) (SOCKET s, long cmd, u_long *argp);
6249 int (PASCAL *pfn_recv) (SOCKET s, char * buf, int len, int flags);
6250 int (PASCAL *pfn_send) (SOCKET s, const char * buf, int len, int flags);
6251 int (PASCAL *pfn_closesocket) (SOCKET s);
6252 int (PASCAL *pfn_shutdown) (SOCKET s, int how);
6253 int (PASCAL *pfn_WSACleanup) (void);
6255 u_short (PASCAL *pfn_htons) (u_short hostshort);
6256 u_short (PASCAL *pfn_ntohs) (u_short netshort);
6257 unsigned long (PASCAL *pfn_inet_addr) (const char * cp);
6258 int (PASCAL *pfn_gethostname) (char * name, int namelen);
6259 struct hostent * (PASCAL *pfn_gethostbyname) (const char * name);
6260 struct servent * (PASCAL *pfn_getservbyname) (const char * name, const char * proto);
6261 int (PASCAL *pfn_getpeername) (SOCKET s, struct sockaddr *addr, int * namelen);
6262 int (PASCAL *pfn_setsockopt) (SOCKET s, int level, int optname,
6263 const char * optval, int optlen);
6264 int (PASCAL *pfn_listen) (SOCKET s, int backlog);
6265 int (PASCAL *pfn_getsockname) (SOCKET s, struct sockaddr * name,
6266 int * namelen);
6267 SOCKET (PASCAL *pfn_accept) (SOCKET s, struct sockaddr * addr, int * addrlen);
6268 int (PASCAL *pfn_recvfrom) (SOCKET s, char * buf, int len, int flags,
6269 struct sockaddr * from, int * fromlen);
6270 int (PASCAL *pfn_sendto) (SOCKET s, const char * buf, int len, int flags,
6271 const struct sockaddr * to, int tolen);
6273 /* SetHandleInformation is only needed to make sockets non-inheritable. */
6274 BOOL (WINAPI *pfn_SetHandleInformation) (HANDLE object, DWORD mask, DWORD flags);
6275 #ifndef HANDLE_FLAG_INHERIT
6276 #define HANDLE_FLAG_INHERIT 1
6277 #endif
6279 HANDLE winsock_lib;
6280 static int winsock_inuse;
6282 BOOL
6283 term_winsock (void)
6285 if (winsock_lib != NULL && winsock_inuse == 0)
6287 release_listen_threads ();
6288 /* Not sure what would cause WSAENETDOWN, or even if it can happen
6289 after WSAStartup returns successfully, but it seems reasonable
6290 to allow unloading winsock anyway in that case. */
6291 if (pfn_WSACleanup () == 0 ||
6292 pfn_WSAGetLastError () == WSAENETDOWN)
6294 if (FreeLibrary (winsock_lib))
6295 winsock_lib = NULL;
6296 return TRUE;
6299 return FALSE;
6302 BOOL
6303 init_winsock (int load_now)
6305 WSADATA winsockData;
6307 if (winsock_lib != NULL)
6308 return TRUE;
6310 pfn_SetHandleInformation
6311 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
6312 "SetHandleInformation");
6314 winsock_lib = LoadLibrary ("Ws2_32.dll");
6316 if (winsock_lib != NULL)
6318 /* dynamically link to socket functions */
6320 #define LOAD_PROC(fn) \
6321 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
6322 goto fail;
6324 LOAD_PROC (WSAStartup);
6325 LOAD_PROC (WSASetLastError);
6326 LOAD_PROC (WSAGetLastError);
6327 LOAD_PROC (WSAEventSelect);
6328 LOAD_PROC (WSACreateEvent);
6329 LOAD_PROC (WSACloseEvent);
6330 LOAD_PROC (socket);
6331 LOAD_PROC (bind);
6332 LOAD_PROC (connect);
6333 LOAD_PROC (ioctlsocket);
6334 LOAD_PROC (recv);
6335 LOAD_PROC (send);
6336 LOAD_PROC (closesocket);
6337 LOAD_PROC (shutdown);
6338 LOAD_PROC (htons);
6339 LOAD_PROC (ntohs);
6340 LOAD_PROC (inet_addr);
6341 LOAD_PROC (gethostname);
6342 LOAD_PROC (gethostbyname);
6343 LOAD_PROC (getservbyname);
6344 LOAD_PROC (getpeername);
6345 LOAD_PROC (WSACleanup);
6346 LOAD_PROC (setsockopt);
6347 LOAD_PROC (listen);
6348 LOAD_PROC (getsockname);
6349 LOAD_PROC (accept);
6350 LOAD_PROC (recvfrom);
6351 LOAD_PROC (sendto);
6352 #undef LOAD_PROC
6354 /* specify version 1.1 of winsock */
6355 if (pfn_WSAStartup (0x101, &winsockData) == 0)
6357 if (winsockData.wVersion != 0x101)
6358 goto fail;
6360 if (!load_now)
6362 /* Report that winsock exists and is usable, but leave
6363 socket functions disabled. I am assuming that calling
6364 WSAStartup does not require any network interaction,
6365 and in particular does not cause or require a dial-up
6366 connection to be established. */
6368 pfn_WSACleanup ();
6369 FreeLibrary (winsock_lib);
6370 winsock_lib = NULL;
6372 winsock_inuse = 0;
6373 return TRUE;
6376 fail:
6377 FreeLibrary (winsock_lib);
6378 winsock_lib = NULL;
6381 return FALSE;
6385 int h_errno = 0;
6387 /* Function to map winsock error codes to errno codes for those errno
6388 code defined in errno.h (errno values not defined by errno.h are
6389 already in nt/inc/sys/socket.h). */
6390 static void
6391 set_errno (void)
6393 int wsa_err;
6395 h_errno = 0;
6396 if (winsock_lib == NULL)
6397 wsa_err = EINVAL;
6398 else
6399 wsa_err = pfn_WSAGetLastError ();
6401 switch (wsa_err)
6403 case WSAEACCES: errno = EACCES; break;
6404 case WSAEBADF: errno = EBADF; break;
6405 case WSAEFAULT: errno = EFAULT; break;
6406 case WSAEINTR: errno = EINTR; break;
6407 case WSAEINVAL: errno = EINVAL; break;
6408 case WSAEMFILE: errno = EMFILE; break;
6409 case WSAENAMETOOLONG: errno = ENAMETOOLONG; break;
6410 case WSAENOTEMPTY: errno = ENOTEMPTY; break;
6411 default: errno = wsa_err; break;
6415 static void
6416 check_errno (void)
6418 h_errno = 0;
6419 if (winsock_lib != NULL)
6420 pfn_WSASetLastError (0);
6423 /* Extend strerror to handle the winsock-specific error codes. */
6424 struct {
6425 int errnum;
6426 char * msg;
6427 } _wsa_errlist[] = {
6428 {WSAEINTR , "Interrupted function call"},
6429 {WSAEBADF , "Bad file descriptor"},
6430 {WSAEACCES , "Permission denied"},
6431 {WSAEFAULT , "Bad address"},
6432 {WSAEINVAL , "Invalid argument"},
6433 {WSAEMFILE , "Too many open files"},
6435 {WSAEWOULDBLOCK , "Resource temporarily unavailable"},
6436 {WSAEINPROGRESS , "Operation now in progress"},
6437 {WSAEALREADY , "Operation already in progress"},
6438 {WSAENOTSOCK , "Socket operation on non-socket"},
6439 {WSAEDESTADDRREQ , "Destination address required"},
6440 {WSAEMSGSIZE , "Message too long"},
6441 {WSAEPROTOTYPE , "Protocol wrong type for socket"},
6442 {WSAENOPROTOOPT , "Bad protocol option"},
6443 {WSAEPROTONOSUPPORT , "Protocol not supported"},
6444 {WSAESOCKTNOSUPPORT , "Socket type not supported"},
6445 {WSAEOPNOTSUPP , "Operation not supported"},
6446 {WSAEPFNOSUPPORT , "Protocol family not supported"},
6447 {WSAEAFNOSUPPORT , "Address family not supported by protocol family"},
6448 {WSAEADDRINUSE , "Address already in use"},
6449 {WSAEADDRNOTAVAIL , "Cannot assign requested address"},
6450 {WSAENETDOWN , "Network is down"},
6451 {WSAENETUNREACH , "Network is unreachable"},
6452 {WSAENETRESET , "Network dropped connection on reset"},
6453 {WSAECONNABORTED , "Software caused connection abort"},
6454 {WSAECONNRESET , "Connection reset by peer"},
6455 {WSAENOBUFS , "No buffer space available"},
6456 {WSAEISCONN , "Socket is already connected"},
6457 {WSAENOTCONN , "Socket is not connected"},
6458 {WSAESHUTDOWN , "Cannot send after socket shutdown"},
6459 {WSAETOOMANYREFS , "Too many references"}, /* not sure */
6460 {WSAETIMEDOUT , "Connection timed out"},
6461 {WSAECONNREFUSED , "Connection refused"},
6462 {WSAELOOP , "Network loop"}, /* not sure */
6463 {WSAENAMETOOLONG , "Name is too long"},
6464 {WSAEHOSTDOWN , "Host is down"},
6465 {WSAEHOSTUNREACH , "No route to host"},
6466 {WSAENOTEMPTY , "Buffer not empty"}, /* not sure */
6467 {WSAEPROCLIM , "Too many processes"},
6468 {WSAEUSERS , "Too many users"}, /* not sure */
6469 {WSAEDQUOT , "Double quote in host name"}, /* really not sure */
6470 {WSAESTALE , "Data is stale"}, /* not sure */
6471 {WSAEREMOTE , "Remote error"}, /* not sure */
6473 {WSASYSNOTREADY , "Network subsystem is unavailable"},
6474 {WSAVERNOTSUPPORTED , "WINSOCK.DLL version out of range"},
6475 {WSANOTINITIALISED , "Winsock not initialized successfully"},
6476 {WSAEDISCON , "Graceful shutdown in progress"},
6477 #ifdef WSAENOMORE
6478 {WSAENOMORE , "No more operations allowed"}, /* not sure */
6479 {WSAECANCELLED , "Operation cancelled"}, /* not sure */
6480 {WSAEINVALIDPROCTABLE , "Invalid procedure table from service provider"},
6481 {WSAEINVALIDPROVIDER , "Invalid service provider version number"},
6482 {WSAEPROVIDERFAILEDINIT , "Unable to initialize a service provider"},
6483 {WSASYSCALLFAILURE , "System call failure"},
6484 {WSASERVICE_NOT_FOUND , "Service not found"}, /* not sure */
6485 {WSATYPE_NOT_FOUND , "Class type not found"},
6486 {WSA_E_NO_MORE , "No more resources available"}, /* really not sure */
6487 {WSA_E_CANCELLED , "Operation already cancelled"}, /* really not sure */
6488 {WSAEREFUSED , "Operation refused"}, /* not sure */
6489 #endif
6491 {WSAHOST_NOT_FOUND , "Host not found"},
6492 {WSATRY_AGAIN , "Authoritative host not found during name lookup"},
6493 {WSANO_RECOVERY , "Non-recoverable error during name lookup"},
6494 {WSANO_DATA , "Valid name, no data record of requested type"},
6496 {-1, NULL}
6499 char *
6500 sys_strerror (int error_no)
6502 int i;
6503 static char unknown_msg[40];
6505 if (error_no >= 0 && error_no < sys_nerr)
6506 return sys_errlist[error_no];
6508 for (i = 0; _wsa_errlist[i].errnum >= 0; i++)
6509 if (_wsa_errlist[i].errnum == error_no)
6510 return _wsa_errlist[i].msg;
6512 sprintf (unknown_msg, "Unidentified error: %d", error_no);
6513 return unknown_msg;
6516 /* [andrewi 3-May-96] I've had conflicting results using both methods,
6517 but I believe the method of keeping the socket handle separate (and
6518 insuring it is not inheritable) is the correct one. */
6520 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
6522 static int socket_to_fd (SOCKET s);
6525 sys_socket (int af, int type, int protocol)
6527 SOCKET s;
6529 if (winsock_lib == NULL)
6531 errno = ENETDOWN;
6532 return INVALID_SOCKET;
6535 check_errno ();
6537 /* call the real socket function */
6538 s = pfn_socket (af, type, protocol);
6540 if (s != INVALID_SOCKET)
6541 return socket_to_fd (s);
6543 set_errno ();
6544 return -1;
6547 /* Convert a SOCKET to a file descriptor. */
6548 static int
6549 socket_to_fd (SOCKET s)
6551 int fd;
6552 child_process * cp;
6554 /* Although under NT 3.5 _open_osfhandle will accept a socket
6555 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
6556 that does not work under NT 3.1. However, we can get the same
6557 effect by using a backdoor function to replace an existing
6558 descriptor handle with the one we want. */
6560 /* allocate a file descriptor (with appropriate flags) */
6561 fd = _open ("NUL:", _O_RDWR);
6562 if (fd >= 0)
6564 /* Make a non-inheritable copy of the socket handle. Note
6565 that it is possible that sockets aren't actually kernel
6566 handles, which appears to be the case on Windows 9x when
6567 the MS Proxy winsock client is installed. */
6569 /* Apparently there is a bug in NT 3.51 with some service
6570 packs, which prevents using DuplicateHandle to make a
6571 socket handle non-inheritable (causes WSACleanup to
6572 hang). The work-around is to use SetHandleInformation
6573 instead if it is available and implemented. */
6574 if (pfn_SetHandleInformation)
6576 pfn_SetHandleInformation ((HANDLE) s, HANDLE_FLAG_INHERIT, 0);
6578 else
6580 HANDLE parent = GetCurrentProcess ();
6581 HANDLE new_s = INVALID_HANDLE_VALUE;
6583 if (DuplicateHandle (parent,
6584 (HANDLE) s,
6585 parent,
6586 &new_s,
6588 FALSE,
6589 DUPLICATE_SAME_ACCESS))
6591 /* It is possible that DuplicateHandle succeeds even
6592 though the socket wasn't really a kernel handle,
6593 because a real handle has the same value. So
6594 test whether the new handle really is a socket. */
6595 long nonblocking = 0;
6596 if (pfn_ioctlsocket ((SOCKET) new_s, FIONBIO, &nonblocking) == 0)
6598 pfn_closesocket (s);
6599 s = (SOCKET) new_s;
6601 else
6603 CloseHandle (new_s);
6608 eassert (fd < MAXDESC);
6609 fd_info[fd].hnd = (HANDLE) s;
6611 /* set our own internal flags */
6612 fd_info[fd].flags = FILE_SOCKET | FILE_BINARY | FILE_READ | FILE_WRITE;
6614 cp = new_child ();
6615 if (cp)
6617 cp->fd = fd;
6618 cp->status = STATUS_READ_ACKNOWLEDGED;
6620 /* attach child_process to fd_info */
6621 if (fd_info[ fd ].cp != NULL)
6623 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd));
6624 emacs_abort ();
6627 fd_info[ fd ].cp = cp;
6629 /* success! */
6630 winsock_inuse++; /* count open sockets */
6631 return fd;
6634 /* clean up */
6635 _close (fd);
6637 else
6638 pfn_closesocket (s);
6639 errno = EMFILE;
6640 return -1;
6644 sys_bind (int s, const struct sockaddr * addr, int namelen)
6646 if (winsock_lib == NULL)
6648 errno = ENOTSOCK;
6649 return SOCKET_ERROR;
6652 check_errno ();
6653 if (fd_info[s].flags & FILE_SOCKET)
6655 int rc = pfn_bind (SOCK_HANDLE (s), addr, namelen);
6656 if (rc == SOCKET_ERROR)
6657 set_errno ();
6658 return rc;
6660 errno = ENOTSOCK;
6661 return SOCKET_ERROR;
6665 sys_connect (int s, const struct sockaddr * name, int namelen)
6667 if (winsock_lib == NULL)
6669 errno = ENOTSOCK;
6670 return SOCKET_ERROR;
6673 check_errno ();
6674 if (fd_info[s].flags & FILE_SOCKET)
6676 int rc = pfn_connect (SOCK_HANDLE (s), name, namelen);
6677 if (rc == SOCKET_ERROR)
6678 set_errno ();
6679 return rc;
6681 errno = ENOTSOCK;
6682 return SOCKET_ERROR;
6685 u_short
6686 sys_htons (u_short hostshort)
6688 return (winsock_lib != NULL) ?
6689 pfn_htons (hostshort) : hostshort;
6692 u_short
6693 sys_ntohs (u_short netshort)
6695 return (winsock_lib != NULL) ?
6696 pfn_ntohs (netshort) : netshort;
6699 unsigned long
6700 sys_inet_addr (const char * cp)
6702 return (winsock_lib != NULL) ?
6703 pfn_inet_addr (cp) : INADDR_NONE;
6707 sys_gethostname (char * name, int namelen)
6709 if (winsock_lib != NULL)
6711 int retval;
6713 check_errno ();
6714 retval = pfn_gethostname (name, namelen);
6715 if (retval == SOCKET_ERROR)
6716 set_errno ();
6717 return retval;
6720 if (namelen > MAX_COMPUTERNAME_LENGTH)
6721 return !GetComputerName (name, (DWORD *)&namelen);
6723 errno = EFAULT;
6724 return SOCKET_ERROR;
6727 struct hostent *
6728 sys_gethostbyname (const char * name)
6730 struct hostent * host;
6731 int h_err = h_errno;
6733 if (winsock_lib == NULL)
6735 h_errno = NO_RECOVERY;
6736 errno = ENETDOWN;
6737 return NULL;
6740 check_errno ();
6741 host = pfn_gethostbyname (name);
6742 if (!host)
6744 set_errno ();
6745 h_errno = errno;
6747 else
6748 h_errno = h_err;
6749 return host;
6752 struct servent *
6753 sys_getservbyname (const char * name, const char * proto)
6755 struct servent * serv;
6757 if (winsock_lib == NULL)
6759 errno = ENETDOWN;
6760 return NULL;
6763 check_errno ();
6764 serv = pfn_getservbyname (name, proto);
6765 if (!serv)
6766 set_errno ();
6767 return serv;
6771 sys_getpeername (int s, struct sockaddr *addr, int * namelen)
6773 if (winsock_lib == NULL)
6775 errno = ENETDOWN;
6776 return SOCKET_ERROR;
6779 check_errno ();
6780 if (fd_info[s].flags & FILE_SOCKET)
6782 int rc = pfn_getpeername (SOCK_HANDLE (s), addr, namelen);
6783 if (rc == SOCKET_ERROR)
6784 set_errno ();
6785 return rc;
6787 errno = ENOTSOCK;
6788 return SOCKET_ERROR;
6792 sys_shutdown (int s, int how)
6794 if (winsock_lib == NULL)
6796 errno = ENETDOWN;
6797 return SOCKET_ERROR;
6800 check_errno ();
6801 if (fd_info[s].flags & FILE_SOCKET)
6803 int rc = pfn_shutdown (SOCK_HANDLE (s), how);
6804 if (rc == SOCKET_ERROR)
6805 set_errno ();
6806 return rc;
6808 errno = ENOTSOCK;
6809 return SOCKET_ERROR;
6813 sys_setsockopt (int s, int level, int optname, const void * optval, int optlen)
6815 if (winsock_lib == NULL)
6817 errno = ENETDOWN;
6818 return SOCKET_ERROR;
6821 check_errno ();
6822 if (fd_info[s].flags & FILE_SOCKET)
6824 int rc = pfn_setsockopt (SOCK_HANDLE (s), level, optname,
6825 (const char *)optval, optlen);
6826 if (rc == SOCKET_ERROR)
6827 set_errno ();
6828 return rc;
6830 errno = ENOTSOCK;
6831 return SOCKET_ERROR;
6835 sys_listen (int s, int backlog)
6837 if (winsock_lib == NULL)
6839 errno = ENETDOWN;
6840 return SOCKET_ERROR;
6843 check_errno ();
6844 if (fd_info[s].flags & FILE_SOCKET)
6846 int rc = pfn_listen (SOCK_HANDLE (s), backlog);
6847 if (rc == SOCKET_ERROR)
6848 set_errno ();
6849 else
6850 fd_info[s].flags |= FILE_LISTEN;
6851 return rc;
6853 errno = ENOTSOCK;
6854 return SOCKET_ERROR;
6858 sys_getsockname (int s, struct sockaddr * name, int * namelen)
6860 if (winsock_lib == NULL)
6862 errno = ENETDOWN;
6863 return SOCKET_ERROR;
6866 check_errno ();
6867 if (fd_info[s].flags & FILE_SOCKET)
6869 int rc = pfn_getsockname (SOCK_HANDLE (s), name, namelen);
6870 if (rc == SOCKET_ERROR)
6871 set_errno ();
6872 return rc;
6874 errno = ENOTSOCK;
6875 return SOCKET_ERROR;
6879 sys_accept (int s, struct sockaddr * addr, int * addrlen)
6881 if (winsock_lib == NULL)
6883 errno = ENETDOWN;
6884 return -1;
6887 check_errno ();
6888 if (fd_info[s].flags & FILE_LISTEN)
6890 SOCKET t = pfn_accept (SOCK_HANDLE (s), addr, addrlen);
6891 int fd = -1;
6892 if (t == INVALID_SOCKET)
6893 set_errno ();
6894 else
6895 fd = socket_to_fd (t);
6897 if (fd >= 0)
6899 fd_info[s].cp->status = STATUS_READ_ACKNOWLEDGED;
6900 ResetEvent (fd_info[s].cp->char_avail);
6902 return fd;
6904 errno = ENOTSOCK;
6905 return -1;
6909 sys_recvfrom (int s, char * buf, int len, int flags,
6910 struct sockaddr * from, int * fromlen)
6912 if (winsock_lib == NULL)
6914 errno = ENETDOWN;
6915 return SOCKET_ERROR;
6918 check_errno ();
6919 if (fd_info[s].flags & FILE_SOCKET)
6921 int rc = pfn_recvfrom (SOCK_HANDLE (s), buf, len, flags, from, fromlen);
6922 if (rc == SOCKET_ERROR)
6923 set_errno ();
6924 return rc;
6926 errno = ENOTSOCK;
6927 return SOCKET_ERROR;
6931 sys_sendto (int s, const char * buf, int len, int flags,
6932 const struct sockaddr * to, int tolen)
6934 if (winsock_lib == NULL)
6936 errno = ENETDOWN;
6937 return SOCKET_ERROR;
6940 check_errno ();
6941 if (fd_info[s].flags & FILE_SOCKET)
6943 int rc = pfn_sendto (SOCK_HANDLE (s), buf, len, flags, to, tolen);
6944 if (rc == SOCKET_ERROR)
6945 set_errno ();
6946 return rc;
6948 errno = ENOTSOCK;
6949 return SOCKET_ERROR;
6952 /* Windows does not have an fcntl function. Provide an implementation
6953 good enough for Emacs. */
6955 fcntl (int s, int cmd, int options)
6957 /* In the w32 Emacs port, fcntl (fd, F_DUPFD_CLOEXEC, fd1) is always
6958 invoked in a context where fd1 is closed and all descriptors less
6959 than fd1 are open, so sys_dup is an adequate implementation. */
6960 if (cmd == F_DUPFD_CLOEXEC)
6961 return sys_dup (s);
6963 if (winsock_lib == NULL)
6965 errno = ENETDOWN;
6966 return -1;
6969 check_errno ();
6970 if (fd_info[s].flags & FILE_SOCKET)
6972 if (cmd == F_SETFL && options == O_NONBLOCK)
6974 unsigned long nblock = 1;
6975 int rc = pfn_ioctlsocket (SOCK_HANDLE (s), FIONBIO, &nblock);
6976 if (rc == SOCKET_ERROR)
6977 set_errno ();
6978 /* Keep track of the fact that we set this to non-blocking. */
6979 fd_info[s].flags |= FILE_NDELAY;
6980 return rc;
6982 else
6984 errno = EINVAL;
6985 return SOCKET_ERROR;
6988 errno = ENOTSOCK;
6989 return SOCKET_ERROR;
6993 /* Shadow main io functions: we need to handle pipes and sockets more
6994 intelligently, and implement non-blocking mode as well. */
6997 sys_close (int fd)
6999 int rc;
7001 if (fd < 0)
7003 errno = EBADF;
7004 return -1;
7007 if (fd < MAXDESC && fd_info[fd].cp)
7009 child_process * cp = fd_info[fd].cp;
7011 fd_info[fd].cp = NULL;
7013 if (CHILD_ACTIVE (cp))
7015 /* if last descriptor to active child_process then cleanup */
7016 int i;
7017 for (i = 0; i < MAXDESC; i++)
7019 if (i == fd)
7020 continue;
7021 if (fd_info[i].cp == cp)
7022 break;
7024 if (i == MAXDESC)
7026 if (fd_info[fd].flags & FILE_SOCKET)
7028 if (winsock_lib == NULL) emacs_abort ();
7030 pfn_shutdown (SOCK_HANDLE (fd), 2);
7031 rc = pfn_closesocket (SOCK_HANDLE (fd));
7033 winsock_inuse--; /* count open sockets */
7035 /* If the process handle is NULL, it's either a socket
7036 or serial connection, or a subprocess that was
7037 already reaped by reap_subprocess, but whose
7038 resources were not yet freed, because its output was
7039 not fully read yet by the time it was reaped. (This
7040 usually happens with async subprocesses whose output
7041 is being read by Emacs.) Otherwise, this process was
7042 not reaped yet, so we set its FD to a negative value
7043 to make sure sys_select will eventually get to
7044 calling the SIGCHLD handler for it, which will then
7045 invoke waitpid and reap_subprocess. */
7046 if (cp->procinfo.hProcess == NULL)
7047 delete_child (cp);
7048 else
7049 cp->fd = -1;
7054 if (fd >= 0 && fd < MAXDESC)
7055 fd_info[fd].flags = 0;
7057 /* Note that sockets do not need special treatment here (at least on
7058 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
7059 closesocket is equivalent to CloseHandle, which is to be expected
7060 because socket handles are fully fledged kernel handles. */
7061 rc = _close (fd);
7063 return rc;
7067 sys_dup (int fd)
7069 int new_fd;
7071 new_fd = _dup (fd);
7072 if (new_fd >= 0 && new_fd < MAXDESC)
7074 /* duplicate our internal info as well */
7075 fd_info[new_fd] = fd_info[fd];
7077 return new_fd;
7081 sys_dup2 (int src, int dst)
7083 int rc;
7085 if (dst < 0 || dst >= MAXDESC)
7087 errno = EBADF;
7088 return -1;
7091 /* make sure we close the destination first if it's a pipe or socket */
7092 if (src != dst && fd_info[dst].flags != 0)
7093 sys_close (dst);
7095 rc = _dup2 (src, dst);
7096 if (rc == 0)
7098 /* duplicate our internal info as well */
7099 fd_info[dst] = fd_info[src];
7101 return rc;
7105 pipe2 (int * phandles, int pipe2_flags)
7107 int rc;
7108 unsigned flags;
7110 eassert (pipe2_flags == O_CLOEXEC);
7112 /* make pipe handles non-inheritable; when we spawn a child, we
7113 replace the relevant handle with an inheritable one. Also put
7114 pipes into binary mode; we will do text mode translation ourselves
7115 if required. */
7116 rc = _pipe (phandles, 0, _O_NOINHERIT | _O_BINARY);
7118 if (rc == 0)
7120 /* Protect against overflow, since Windows can open more handles than
7121 our fd_info array has room for. */
7122 if (phandles[0] >= MAXDESC || phandles[1] >= MAXDESC)
7124 _close (phandles[0]);
7125 _close (phandles[1]);
7126 errno = EMFILE;
7127 rc = -1;
7129 else
7131 flags = FILE_PIPE | FILE_READ | FILE_BINARY;
7132 fd_info[phandles[0]].flags = flags;
7134 flags = FILE_PIPE | FILE_WRITE | FILE_BINARY;
7135 fd_info[phandles[1]].flags = flags;
7139 return rc;
7142 /* Function to do blocking read of one byte, needed to implement
7143 select. It is only allowed on communication ports, sockets, or
7144 pipes. */
7146 _sys_read_ahead (int fd)
7148 child_process * cp;
7149 int rc;
7151 if (fd < 0 || fd >= MAXDESC)
7152 return STATUS_READ_ERROR;
7154 cp = fd_info[fd].cp;
7156 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
7157 return STATUS_READ_ERROR;
7159 if ((fd_info[fd].flags & (FILE_PIPE | FILE_SERIAL | FILE_SOCKET)) == 0
7160 || (fd_info[fd].flags & FILE_READ) == 0)
7162 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd));
7163 emacs_abort ();
7166 cp->status = STATUS_READ_IN_PROGRESS;
7168 if (fd_info[fd].flags & FILE_PIPE)
7170 rc = _read (fd, &cp->chr, sizeof (char));
7172 /* Give subprocess time to buffer some more output for us before
7173 reporting that input is available; we need this because Windows 95
7174 connects DOS programs to pipes by making the pipe appear to be
7175 the normal console stdout - as a result most DOS programs will
7176 write to stdout without buffering, ie. one character at a
7177 time. Even some W32 programs do this - "dir" in a command
7178 shell on NT is very slow if we don't do this. */
7179 if (rc > 0)
7181 int wait = w32_pipe_read_delay;
7183 if (wait > 0)
7184 Sleep (wait);
7185 else if (wait < 0)
7186 while (++wait <= 0)
7187 /* Yield remainder of our time slice, effectively giving a
7188 temporary priority boost to the child process. */
7189 Sleep (0);
7192 else if (fd_info[fd].flags & FILE_SERIAL)
7194 HANDLE hnd = fd_info[fd].hnd;
7195 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
7196 COMMTIMEOUTS ct;
7198 /* Configure timeouts for blocking read. */
7199 if (!GetCommTimeouts (hnd, &ct))
7201 cp->status = STATUS_READ_ERROR;
7202 return STATUS_READ_ERROR;
7204 ct.ReadIntervalTimeout = 0;
7205 ct.ReadTotalTimeoutMultiplier = 0;
7206 ct.ReadTotalTimeoutConstant = 0;
7207 if (!SetCommTimeouts (hnd, &ct))
7209 cp->status = STATUS_READ_ERROR;
7210 return STATUS_READ_ERROR;
7213 if (!ReadFile (hnd, &cp->chr, sizeof (char), (DWORD*) &rc, ovl))
7215 if (GetLastError () != ERROR_IO_PENDING)
7217 cp->status = STATUS_READ_ERROR;
7218 return STATUS_READ_ERROR;
7220 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
7222 cp->status = STATUS_READ_ERROR;
7223 return STATUS_READ_ERROR;
7227 else if (fd_info[fd].flags & FILE_SOCKET)
7229 unsigned long nblock = 0;
7230 /* We always want this to block, so temporarily disable NDELAY. */
7231 if (fd_info[fd].flags & FILE_NDELAY)
7232 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
7234 rc = pfn_recv (SOCK_HANDLE (fd), &cp->chr, sizeof (char), 0);
7236 if (fd_info[fd].flags & FILE_NDELAY)
7238 nblock = 1;
7239 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
7243 if (rc == sizeof (char))
7244 cp->status = STATUS_READ_SUCCEEDED;
7245 else
7246 cp->status = STATUS_READ_FAILED;
7248 return cp->status;
7252 _sys_wait_accept (int fd)
7254 HANDLE hEv;
7255 child_process * cp;
7256 int rc;
7258 if (fd < 0 || fd >= MAXDESC)
7259 return STATUS_READ_ERROR;
7261 cp = fd_info[fd].cp;
7263 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
7264 return STATUS_READ_ERROR;
7266 cp->status = STATUS_READ_FAILED;
7268 hEv = pfn_WSACreateEvent ();
7269 rc = pfn_WSAEventSelect (SOCK_HANDLE (fd), hEv, FD_ACCEPT);
7270 if (rc != SOCKET_ERROR)
7272 do {
7273 rc = WaitForSingleObject (hEv, 500);
7274 Sleep (5);
7275 } while (rc == WAIT_TIMEOUT
7276 && cp->status != STATUS_READ_ERROR
7277 && cp->char_avail);
7278 pfn_WSAEventSelect (SOCK_HANDLE (fd), NULL, 0);
7279 if (rc == WAIT_OBJECT_0)
7280 cp->status = STATUS_READ_SUCCEEDED;
7282 pfn_WSACloseEvent (hEv);
7284 return cp->status;
7288 sys_read (int fd, char * buffer, unsigned int count)
7290 int nchars;
7291 int to_read;
7292 DWORD waiting;
7293 char * orig_buffer = buffer;
7295 if (fd < 0)
7297 errno = EBADF;
7298 return -1;
7301 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
7303 child_process *cp = fd_info[fd].cp;
7305 if ((fd_info[fd].flags & FILE_READ) == 0)
7307 errno = EBADF;
7308 return -1;
7311 nchars = 0;
7313 /* re-read CR carried over from last read */
7314 if (fd_info[fd].flags & FILE_LAST_CR)
7316 if (fd_info[fd].flags & FILE_BINARY) emacs_abort ();
7317 *buffer++ = 0x0d;
7318 count--;
7319 nchars++;
7320 fd_info[fd].flags &= ~FILE_LAST_CR;
7323 /* presence of a child_process structure means we are operating in
7324 non-blocking mode - otherwise we just call _read directly.
7325 Note that the child_process structure might be missing because
7326 reap_subprocess has been called; in this case the pipe is
7327 already broken, so calling _read on it is okay. */
7328 if (cp)
7330 int current_status = cp->status;
7332 switch (current_status)
7334 case STATUS_READ_FAILED:
7335 case STATUS_READ_ERROR:
7336 /* report normal EOF if nothing in buffer */
7337 if (nchars <= 0)
7338 fd_info[fd].flags |= FILE_AT_EOF;
7339 return nchars;
7341 case STATUS_READ_READY:
7342 case STATUS_READ_IN_PROGRESS:
7343 DebPrint (("sys_read called when read is in progress\n"));
7344 errno = EWOULDBLOCK;
7345 return -1;
7347 case STATUS_READ_SUCCEEDED:
7348 /* consume read-ahead char */
7349 *buffer++ = cp->chr;
7350 count--;
7351 nchars++;
7352 cp->status = STATUS_READ_ACKNOWLEDGED;
7353 ResetEvent (cp->char_avail);
7355 case STATUS_READ_ACKNOWLEDGED:
7356 break;
7358 default:
7359 DebPrint (("sys_read: bad status %d\n", current_status));
7360 errno = EBADF;
7361 return -1;
7364 if (fd_info[fd].flags & FILE_PIPE)
7366 PeekNamedPipe ((HANDLE) _get_osfhandle (fd), NULL, 0, NULL, &waiting, NULL);
7367 to_read = min (waiting, (DWORD) count);
7369 if (to_read > 0)
7370 nchars += _read (fd, buffer, to_read);
7372 else if (fd_info[fd].flags & FILE_SERIAL)
7374 HANDLE hnd = fd_info[fd].hnd;
7375 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
7376 int rc = 0;
7377 COMMTIMEOUTS ct;
7379 if (count > 0)
7381 /* Configure timeouts for non-blocking read. */
7382 if (!GetCommTimeouts (hnd, &ct))
7384 errno = EIO;
7385 return -1;
7387 ct.ReadIntervalTimeout = MAXDWORD;
7388 ct.ReadTotalTimeoutMultiplier = 0;
7389 ct.ReadTotalTimeoutConstant = 0;
7390 if (!SetCommTimeouts (hnd, &ct))
7392 errno = EIO;
7393 return -1;
7396 if (!ResetEvent (ovl->hEvent))
7398 errno = EIO;
7399 return -1;
7401 if (!ReadFile (hnd, buffer, count, (DWORD*) &rc, ovl))
7403 if (GetLastError () != ERROR_IO_PENDING)
7405 errno = EIO;
7406 return -1;
7408 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
7410 errno = EIO;
7411 return -1;
7414 nchars += rc;
7417 else /* FILE_SOCKET */
7419 if (winsock_lib == NULL) emacs_abort ();
7421 /* do the equivalent of a non-blocking read */
7422 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONREAD, &waiting);
7423 if (waiting == 0 && nchars == 0)
7425 errno = EWOULDBLOCK;
7426 return -1;
7429 if (waiting)
7431 /* always use binary mode for sockets */
7432 int res = pfn_recv (SOCK_HANDLE (fd), buffer, count, 0);
7433 if (res == SOCKET_ERROR)
7435 DebPrint (("sys_read.recv failed with error %d on socket %ld\n",
7436 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
7437 set_errno ();
7438 return -1;
7440 nchars += res;
7444 else
7446 int nread = _read (fd, buffer, count);
7447 if (nread >= 0)
7448 nchars += nread;
7449 else if (nchars == 0)
7450 nchars = nread;
7453 if (nchars <= 0)
7454 fd_info[fd].flags |= FILE_AT_EOF;
7455 /* Perform text mode translation if required. */
7456 else if ((fd_info[fd].flags & FILE_BINARY) == 0)
7458 nchars = crlf_to_lf (nchars, orig_buffer);
7459 /* If buffer contains only CR, return that. To be absolutely
7460 sure we should attempt to read the next char, but in
7461 practice a CR to be followed by LF would not appear by
7462 itself in the buffer. */
7463 if (nchars > 1 && orig_buffer[nchars - 1] == 0x0d)
7465 fd_info[fd].flags |= FILE_LAST_CR;
7466 nchars--;
7470 else
7471 nchars = _read (fd, buffer, count);
7473 return nchars;
7476 /* From w32xfns.c */
7477 extern HANDLE interrupt_handle;
7479 /* For now, don't bother with a non-blocking mode */
7481 sys_write (int fd, const void * buffer, unsigned int count)
7483 int nchars;
7485 if (fd < 0)
7487 errno = EBADF;
7488 return -1;
7491 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
7493 if ((fd_info[fd].flags & FILE_WRITE) == 0)
7495 errno = EBADF;
7496 return -1;
7499 /* Perform text mode translation if required. */
7500 if ((fd_info[fd].flags & FILE_BINARY) == 0)
7502 char * tmpbuf = alloca (count * 2);
7503 unsigned char * src = (void *)buffer;
7504 unsigned char * dst = tmpbuf;
7505 int nbytes = count;
7507 while (1)
7509 unsigned char *next;
7510 /* copy next line or remaining bytes */
7511 next = _memccpy (dst, src, '\n', nbytes);
7512 if (next)
7514 /* copied one line ending with '\n' */
7515 int copied = next - dst;
7516 nbytes -= copied;
7517 src += copied;
7518 /* insert '\r' before '\n' */
7519 next[-1] = '\r';
7520 next[0] = '\n';
7521 dst = next + 1;
7522 count++;
7524 else
7525 /* copied remaining partial line -> now finished */
7526 break;
7528 buffer = tmpbuf;
7532 if (fd < MAXDESC && fd_info[fd].flags & FILE_SERIAL)
7534 HANDLE hnd = (HANDLE) _get_osfhandle (fd);
7535 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_write;
7536 HANDLE wait_hnd[2] = { interrupt_handle, ovl->hEvent };
7537 DWORD active = 0;
7539 if (!WriteFile (hnd, buffer, count, (DWORD*) &nchars, ovl))
7541 if (GetLastError () != ERROR_IO_PENDING)
7543 errno = EIO;
7544 return -1;
7546 if (detect_input_pending ())
7547 active = MsgWaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE,
7548 QS_ALLINPUT);
7549 else
7550 active = WaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE);
7551 if (active == WAIT_OBJECT_0)
7552 { /* User pressed C-g, cancel write, then leave. Don't bother
7553 cleaning up as we may only get stuck in buggy drivers. */
7554 PurgeComm (hnd, PURGE_TXABORT | PURGE_TXCLEAR);
7555 CancelIo (hnd);
7556 errno = EIO;
7557 return -1;
7559 if (active == WAIT_OBJECT_0 + 1
7560 && !GetOverlappedResult (hnd, ovl, (DWORD*) &nchars, TRUE))
7562 errno = EIO;
7563 return -1;
7567 else if (fd < MAXDESC && fd_info[fd].flags & FILE_SOCKET)
7569 unsigned long nblock = 0;
7570 if (winsock_lib == NULL) emacs_abort ();
7572 /* TODO: implement select() properly so non-blocking I/O works. */
7573 /* For now, make sure the write blocks. */
7574 if (fd_info[fd].flags & FILE_NDELAY)
7575 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
7577 nchars = pfn_send (SOCK_HANDLE (fd), buffer, count, 0);
7579 /* Set the socket back to non-blocking if it was before,
7580 for other operations that support it. */
7581 if (fd_info[fd].flags & FILE_NDELAY)
7583 nblock = 1;
7584 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
7587 if (nchars == SOCKET_ERROR)
7589 DebPrint (("sys_write.send failed with error %d on socket %ld\n",
7590 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
7591 set_errno ();
7594 else
7596 /* Some networked filesystems don't like too large writes, so
7597 break them into smaller chunks. See the Comments section of
7598 the MSDN documentation of WriteFile for details behind the
7599 choice of the value of CHUNK below. See also the thread
7600 http://thread.gmane.org/gmane.comp.version-control.git/145294
7601 in the git mailing list. */
7602 const unsigned char *p = buffer;
7603 const unsigned chunk = 30 * 1024 * 1024;
7605 nchars = 0;
7606 while (count > 0)
7608 unsigned this_chunk = count < chunk ? count : chunk;
7609 int n = _write (fd, p, this_chunk);
7611 nchars += n;
7612 if (n < 0)
7614 nchars = n;
7615 break;
7617 else if (n < this_chunk)
7618 break;
7619 count -= n;
7620 p += n;
7624 return nchars;
7628 /* Emulation of SIOCGIFCONF and getifaddrs, see process.c. */
7630 extern Lisp_Object conv_sockaddr_to_lisp (struct sockaddr *, int);
7632 /* Return information about network interface IFNAME, or about all
7633 interfaces (if IFNAME is nil). */
7634 static Lisp_Object
7635 network_interface_get_info (Lisp_Object ifname)
7637 ULONG ainfo_len = sizeof (IP_ADAPTER_INFO);
7638 IP_ADAPTER_INFO *adapter, *ainfo = xmalloc (ainfo_len);
7639 DWORD retval = get_adapters_info (ainfo, &ainfo_len);
7640 Lisp_Object res = Qnil;
7642 if (retval == ERROR_BUFFER_OVERFLOW)
7644 ainfo = xrealloc (ainfo, ainfo_len);
7645 retval = get_adapters_info (ainfo, &ainfo_len);
7648 if (retval == ERROR_SUCCESS)
7650 int eth_count = 0, tr_count = 0, fddi_count = 0, ppp_count = 0;
7651 int sl_count = 0, wlan_count = 0, lo_count = 0, ifx_count = 0;
7652 int if_num;
7653 struct sockaddr_in sa;
7655 /* For the below, we need some winsock functions, so make sure
7656 the winsock DLL is loaded. If we cannot successfully load
7657 it, they will have no use of the information we provide,
7658 anyway, so punt. */
7659 if (!winsock_lib && !init_winsock (1))
7660 goto done;
7662 for (adapter = ainfo; adapter; adapter = adapter->Next)
7664 char namebuf[MAX_ADAPTER_NAME_LENGTH + 4];
7665 u_long ip_addr;
7666 /* Present Unix-compatible interface names, instead of the
7667 Windows names, which are really GUIDs not readable by
7668 humans. */
7669 static const char *ifmt[] = {
7670 "eth%d", "tr%d", "fddi%d", "ppp%d", "sl%d", "wlan%d",
7671 "lo", "ifx%d"
7673 enum {
7674 NONE = -1,
7675 ETHERNET = 0,
7676 TOKENRING = 1,
7677 FDDI = 2,
7678 PPP = 3,
7679 SLIP = 4,
7680 WLAN = 5,
7681 LOOPBACK = 6,
7682 OTHER_IF = 7
7683 } ifmt_idx;
7685 switch (adapter->Type)
7687 case MIB_IF_TYPE_ETHERNET:
7688 /* Windows before Vista reports wireless adapters as
7689 Ethernet. Work around by looking at the Description
7690 string. */
7691 if (strstr (adapter->Description, "Wireless "))
7693 ifmt_idx = WLAN;
7694 if_num = wlan_count++;
7696 else
7698 ifmt_idx = ETHERNET;
7699 if_num = eth_count++;
7701 break;
7702 case MIB_IF_TYPE_TOKENRING:
7703 ifmt_idx = TOKENRING;
7704 if_num = tr_count++;
7705 break;
7706 case MIB_IF_TYPE_FDDI:
7707 ifmt_idx = FDDI;
7708 if_num = fddi_count++;
7709 break;
7710 case MIB_IF_TYPE_PPP:
7711 ifmt_idx = PPP;
7712 if_num = ppp_count++;
7713 break;
7714 case MIB_IF_TYPE_SLIP:
7715 ifmt_idx = SLIP;
7716 if_num = sl_count++;
7717 break;
7718 case IF_TYPE_IEEE80211:
7719 ifmt_idx = WLAN;
7720 if_num = wlan_count++;
7721 break;
7722 case MIB_IF_TYPE_LOOPBACK:
7723 if (lo_count < 0)
7725 ifmt_idx = LOOPBACK;
7726 if_num = lo_count++;
7728 else
7729 ifmt_idx = NONE;
7730 break;
7731 default:
7732 ifmt_idx = OTHER_IF;
7733 if_num = ifx_count++;
7734 break;
7736 if (ifmt_idx == NONE)
7737 continue;
7738 sprintf (namebuf, ifmt[ifmt_idx], if_num);
7740 sa.sin_family = AF_INET;
7741 ip_addr = sys_inet_addr (adapter->IpAddressList.IpAddress.String);
7742 if (ip_addr == INADDR_NONE)
7744 /* Bogus address, skip this interface. */
7745 continue;
7747 sa.sin_addr.s_addr = ip_addr;
7748 sa.sin_port = 0;
7749 if (NILP (ifname))
7750 res = Fcons (Fcons (build_string (namebuf),
7751 conv_sockaddr_to_lisp ((struct sockaddr*) &sa,
7752 sizeof (struct sockaddr))),
7753 res);
7754 else if (strcmp (namebuf, SSDATA (ifname)) == 0)
7756 Lisp_Object hwaddr = Fmake_vector (make_number (6), Qnil);
7757 register struct Lisp_Vector *p = XVECTOR (hwaddr);
7758 Lisp_Object flags = Qnil;
7759 int n;
7760 u_long net_mask;
7762 /* Flags. We guess most of them by type, since the
7763 Windows flags are different and hard to get by. */
7764 flags = Fcons (intern ("up"), flags);
7765 if (ifmt_idx == ETHERNET || ifmt_idx == WLAN)
7767 flags = Fcons (intern ("broadcast"), flags);
7768 flags = Fcons (intern ("multicast"), flags);
7770 flags = Fcons (intern ("running"), flags);
7771 if (ifmt_idx == PPP)
7773 flags = Fcons (intern ("pointopoint"), flags);
7774 flags = Fcons (intern ("noarp"), flags);
7776 if (adapter->HaveWins)
7777 flags = Fcons (intern ("WINS"), flags);
7778 if (adapter->DhcpEnabled)
7779 flags = Fcons (intern ("dynamic"), flags);
7781 res = Fcons (flags, res);
7783 /* Hardware address and its family. */
7784 for (n = 0; n < adapter->AddressLength; n++)
7785 p->u.contents[n] = make_number ((int) adapter->Address[n]);
7786 /* Windows does not support AF_LINK or AF_PACKET family
7787 of addresses. Use an arbitrary family number that is
7788 identical to what GNU/Linux returns. */
7789 res = Fcons (Fcons (make_number (1), hwaddr), res);
7791 /* Network mask. */
7792 sa.sin_family = AF_INET;
7793 net_mask = sys_inet_addr (adapter->IpAddressList.IpMask.String);
7794 if (net_mask != INADDR_NONE)
7796 sa.sin_addr.s_addr = net_mask;
7797 sa.sin_port = 0;
7798 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
7799 sizeof (struct sockaddr)),
7800 res);
7802 else
7803 res = Fcons (Qnil, res);
7805 sa.sin_family = AF_INET;
7806 if (ip_addr != INADDR_NONE)
7808 /* Broadcast address is only reported by
7809 GetAdaptersAddresses, which is of limited
7810 availability. Generate it on our own. */
7811 u_long bcast_addr = (ip_addr & net_mask) | ~net_mask;
7813 sa.sin_addr.s_addr = bcast_addr;
7814 sa.sin_port = 0;
7815 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
7816 sizeof (struct sockaddr)),
7817 res);
7819 /* IP address. */
7820 sa.sin_addr.s_addr = ip_addr;
7821 sa.sin_port = 0;
7822 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
7823 sizeof (struct sockaddr)),
7824 res);
7826 else
7827 res = Fcons (Qnil, Fcons (Qnil, res));
7830 /* GetAdaptersInfo is documented to not report loopback
7831 interfaces, so we generate one out of thin air. */
7832 if (!lo_count)
7834 sa.sin_family = AF_INET;
7835 sa.sin_port = 0;
7836 if (NILP (ifname))
7838 sa.sin_addr.s_addr = sys_inet_addr ("127.0.0.1");
7839 res = Fcons (Fcons (build_string ("lo"),
7840 conv_sockaddr_to_lisp ((struct sockaddr*) &sa,
7841 sizeof (struct sockaddr))),
7842 res);
7844 else if (strcmp (SSDATA (ifname), "lo") == 0)
7846 res = Fcons (Fcons (intern ("running"),
7847 Fcons (intern ("loopback"),
7848 Fcons (intern ("up"), Qnil))), Qnil);
7849 /* 772 is what 3 different GNU/Linux systems report for
7850 the loopback interface. */
7851 res = Fcons (Fcons (make_number (772),
7852 Fmake_vector (make_number (6),
7853 make_number (0))),
7854 res);
7855 sa.sin_addr.s_addr = sys_inet_addr ("255.0.0.0");
7856 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
7857 sizeof (struct sockaddr)),
7858 res);
7859 sa.sin_addr.s_addr = sys_inet_addr ("0.0.0.0");
7860 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
7861 sizeof (struct sockaddr)),
7862 res);
7863 sa.sin_addr.s_addr = sys_inet_addr ("127.0.0.1");
7864 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
7865 sizeof (struct sockaddr)),
7866 res);
7872 done:
7873 xfree (ainfo);
7874 return res;
7877 Lisp_Object
7878 network_interface_list (void)
7880 return network_interface_get_info (Qnil);
7883 Lisp_Object
7884 network_interface_info (Lisp_Object ifname)
7886 return network_interface_get_info (ifname);
7890 /* The Windows CRT functions are "optimized for speed", so they don't
7891 check for timezone and DST changes if they were last called less
7892 than 1 minute ago (see http://support.microsoft.com/kb/821231). So
7893 all Emacs features that repeatedly call time functions (e.g.,
7894 display-time) are in real danger of missing timezone and DST
7895 changes. Calling tzset before each localtime call fixes that. */
7896 struct tm *
7897 sys_localtime (const time_t *t)
7899 tzset ();
7900 return localtime (t);
7905 /* Try loading LIBRARY_ID from the file(s) specified in
7906 Vdynamic_library_alist. If the library is loaded successfully,
7907 return the handle of the DLL, and record the filename in the
7908 property :loaded-from of LIBRARY_ID. If the library could not be
7909 found, or when it was already loaded (because the handle is not
7910 recorded anywhere, and so is lost after use), return NULL.
7912 We could also save the handle in :loaded-from, but currently
7913 there's no use case for it. */
7914 HMODULE
7915 w32_delayed_load (Lisp_Object library_id)
7917 HMODULE library_dll = NULL;
7919 CHECK_SYMBOL (library_id);
7921 if (CONSP (Vdynamic_library_alist)
7922 && NILP (Fassq (library_id, Vlibrary_cache)))
7924 Lisp_Object found = Qnil;
7925 Lisp_Object dlls = Fassq (library_id, Vdynamic_library_alist);
7927 if (CONSP (dlls))
7928 for (dlls = XCDR (dlls); CONSP (dlls); dlls = XCDR (dlls))
7930 CHECK_STRING_CAR (dlls);
7931 if ((library_dll = LoadLibrary (SDATA (XCAR (dlls)))))
7933 char name[MAX_PATH];
7934 DWORD len;
7936 len = GetModuleFileNameA (library_dll, name, sizeof (name));
7937 found = Fcons (XCAR (dlls),
7938 (len > 0)
7939 /* Possibly truncated */
7940 ? make_specified_string (name, -1, len, 1)
7941 : Qnil);
7942 break;
7946 Fput (library_id, QCloaded_from, found);
7949 return library_dll;
7953 void
7954 check_windows_init_file (void)
7956 /* A common indication that Emacs is not installed properly is when
7957 it cannot find the Windows installation file. If this file does
7958 not exist in the expected place, tell the user. */
7960 if (!noninteractive && !inhibit_window_system
7961 /* Vload_path is not yet initialized when we are loading
7962 loadup.el. */
7963 && NILP (Vpurify_flag))
7965 Lisp_Object init_file;
7966 int fd;
7968 init_file = build_string ("term/w32-win");
7969 fd = openp (Vload_path, init_file, Fget_load_suffixes (), NULL, Qnil);
7970 if (fd < 0)
7972 Lisp_Object load_path_print = Fprin1_to_string (Vload_path, Qnil);
7973 char *init_file_name = SDATA (init_file);
7974 char *load_path = SDATA (load_path_print);
7975 char *buffer = alloca (1024
7976 + strlen (init_file_name)
7977 + strlen (load_path));
7979 sprintf (buffer,
7980 "The Emacs Windows initialization file \"%s.el\" "
7981 "could not be found in your Emacs installation. "
7982 "Emacs checked the following directories for this file:\n"
7983 "\n%s\n\n"
7984 "When Emacs cannot find this file, it usually means that it "
7985 "was not installed properly, or its distribution file was "
7986 "not unpacked properly.\nSee the README.W32 file in the "
7987 "top-level Emacs directory for more information.",
7988 init_file_name, load_path);
7989 MessageBox (NULL,
7990 buffer,
7991 "Emacs Abort Dialog",
7992 MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
7993 /* Use the low-level system abort. */
7994 abort ();
7996 else
7998 _close (fd);
8003 void
8004 term_ntproc (int ignored)
8006 (void)ignored;
8008 term_timers ();
8010 /* shutdown the socket interface if necessary */
8011 term_winsock ();
8013 term_w32select ();
8016 void
8017 init_ntproc (int dumping)
8019 sigset_t initial_mask = 0;
8021 /* Initialize the socket interface now if available and requested by
8022 the user by defining PRELOAD_WINSOCK; otherwise loading will be
8023 delayed until open-network-stream is called (w32-has-winsock can
8024 also be used to dynamically load or reload winsock).
8026 Conveniently, init_environment is called before us, so
8027 PRELOAD_WINSOCK can be set in the registry. */
8029 /* Always initialize this correctly. */
8030 winsock_lib = NULL;
8032 if (getenv ("PRELOAD_WINSOCK") != NULL)
8033 init_winsock (TRUE);
8035 /* Initial preparation for subprocess support: replace our standard
8036 handles with non-inheritable versions. */
8038 HANDLE parent;
8039 HANDLE stdin_save = INVALID_HANDLE_VALUE;
8040 HANDLE stdout_save = INVALID_HANDLE_VALUE;
8041 HANDLE stderr_save = INVALID_HANDLE_VALUE;
8043 parent = GetCurrentProcess ();
8045 /* ignore errors when duplicating and closing; typically the
8046 handles will be invalid when running as a gui program. */
8047 DuplicateHandle (parent,
8048 GetStdHandle (STD_INPUT_HANDLE),
8049 parent,
8050 &stdin_save,
8052 FALSE,
8053 DUPLICATE_SAME_ACCESS);
8055 DuplicateHandle (parent,
8056 GetStdHandle (STD_OUTPUT_HANDLE),
8057 parent,
8058 &stdout_save,
8060 FALSE,
8061 DUPLICATE_SAME_ACCESS);
8063 DuplicateHandle (parent,
8064 GetStdHandle (STD_ERROR_HANDLE),
8065 parent,
8066 &stderr_save,
8068 FALSE,
8069 DUPLICATE_SAME_ACCESS);
8071 fclose (stdin);
8072 fclose (stdout);
8073 fclose (stderr);
8075 if (stdin_save != INVALID_HANDLE_VALUE)
8076 _open_osfhandle ((intptr_t) stdin_save, O_TEXT);
8077 else
8078 _open ("nul", O_TEXT | O_NOINHERIT | O_RDONLY);
8079 _fdopen (0, "r");
8081 if (stdout_save != INVALID_HANDLE_VALUE)
8082 _open_osfhandle ((intptr_t) stdout_save, O_TEXT);
8083 else
8084 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
8085 _fdopen (1, "w");
8087 if (stderr_save != INVALID_HANDLE_VALUE)
8088 _open_osfhandle ((intptr_t) stderr_save, O_TEXT);
8089 else
8090 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
8091 _fdopen (2, "w");
8094 /* unfortunately, atexit depends on implementation of malloc */
8095 /* atexit (term_ntproc); */
8096 if (!dumping)
8098 /* Make sure we start with all signals unblocked. */
8099 sigprocmask (SIG_SETMASK, &initial_mask, NULL);
8100 signal (SIGABRT, term_ntproc);
8102 init_timers ();
8104 /* determine which drives are fixed, for GetCachedVolumeInformation */
8106 /* GetDriveType must have trailing backslash. */
8107 char drive[] = "A:\\";
8109 /* Loop over all possible drive letters */
8110 while (*drive <= 'Z')
8112 /* Record if this drive letter refers to a fixed drive. */
8113 fixed_drives[DRIVE_INDEX (*drive)] =
8114 (GetDriveType (drive) == DRIVE_FIXED);
8116 (*drive)++;
8119 /* Reset the volume info cache. */
8120 volume_cache = NULL;
8125 shutdown_handler ensures that buffers' autosave files are
8126 up to date when the user logs off, or the system shuts down.
8128 static BOOL WINAPI
8129 shutdown_handler (DWORD type)
8131 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
8132 if (type == CTRL_CLOSE_EVENT /* User closes console window. */
8133 || type == CTRL_LOGOFF_EVENT /* User logs off. */
8134 || type == CTRL_SHUTDOWN_EVENT) /* User shutsdown. */
8136 /* Shut down cleanly, making sure autosave files are up to date. */
8137 shut_down_emacs (0, Qnil);
8140 /* Allow other handlers to handle this signal. */
8141 return FALSE;
8145 globals_of_w32 is used to initialize those global variables that
8146 must always be initialized on startup even when the global variable
8147 initialized is non zero (see the function main in emacs.c).
8149 void
8150 globals_of_w32 (void)
8152 HMODULE kernel32 = GetModuleHandle ("kernel32.dll");
8154 get_process_times_fn = (GetProcessTimes_Proc)
8155 GetProcAddress (kernel32, "GetProcessTimes");
8157 DEFSYM (QCloaded_from, ":loaded-from");
8159 g_b_init_is_windows_9x = 0;
8160 g_b_init_open_process_token = 0;
8161 g_b_init_get_token_information = 0;
8162 g_b_init_lookup_account_sid = 0;
8163 g_b_init_get_sid_sub_authority = 0;
8164 g_b_init_get_sid_sub_authority_count = 0;
8165 g_b_init_get_security_info = 0;
8166 g_b_init_get_file_security = 0;
8167 g_b_init_get_security_descriptor_owner = 0;
8168 g_b_init_get_security_descriptor_group = 0;
8169 g_b_init_is_valid_sid = 0;
8170 g_b_init_create_toolhelp32_snapshot = 0;
8171 g_b_init_process32_first = 0;
8172 g_b_init_process32_next = 0;
8173 g_b_init_open_thread_token = 0;
8174 g_b_init_impersonate_self = 0;
8175 g_b_init_revert_to_self = 0;
8176 g_b_init_get_process_memory_info = 0;
8177 g_b_init_get_process_working_set_size = 0;
8178 g_b_init_global_memory_status = 0;
8179 g_b_init_global_memory_status_ex = 0;
8180 g_b_init_equal_sid = 0;
8181 g_b_init_copy_sid = 0;
8182 g_b_init_get_length_sid = 0;
8183 g_b_init_get_native_system_info = 0;
8184 g_b_init_get_system_times = 0;
8185 g_b_init_create_symbolic_link = 0;
8186 g_b_init_get_security_descriptor_dacl = 0;
8187 g_b_init_convert_sd_to_sddl = 0;
8188 g_b_init_convert_sddl_to_sd = 0;
8189 g_b_init_is_valid_security_descriptor = 0;
8190 g_b_init_set_file_security = 0;
8191 g_b_init_get_adapters_info = 0;
8192 num_of_processors = 0;
8193 /* The following sets a handler for shutdown notifications for
8194 console apps. This actually applies to Emacs in both console and
8195 GUI modes, since we had to fool windows into thinking emacs is a
8196 console application to get console mode to work. */
8197 SetConsoleCtrlHandler (shutdown_handler, TRUE);
8199 /* "None" is the default group name on standalone workstations. */
8200 strcpy (dflt_group_name, "None");
8202 /* Reset, in case it has some value inherited from dump time. */
8203 w32_stat_get_owner_group = 0;
8205 /* If w32_unicode_filenames is non-zero, we will be using Unicode
8206 (a.k.a. "wide") APIs to invoke functions that accept file
8207 names. */
8208 if (is_windows_9x ())
8209 w32_unicode_filenames = 0;
8210 else
8211 w32_unicode_filenames = 1;
8214 /* For make-serial-process */
8216 serial_open (Lisp_Object port_obj)
8218 char *port = SSDATA (port_obj);
8219 HANDLE hnd;
8220 child_process *cp;
8221 int fd = -1;
8223 hnd = CreateFile (port, GENERIC_READ | GENERIC_WRITE, 0, 0,
8224 OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
8225 if (hnd == INVALID_HANDLE_VALUE)
8226 error ("Could not open %s", port);
8227 fd = (int) _open_osfhandle ((intptr_t) hnd, 0);
8228 if (fd == -1)
8229 error ("Could not open %s", port);
8231 cp = new_child ();
8232 if (!cp)
8233 error ("Could not create child process");
8234 cp->fd = fd;
8235 cp->status = STATUS_READ_ACKNOWLEDGED;
8236 fd_info[ fd ].hnd = hnd;
8237 fd_info[ fd ].flags |=
8238 FILE_READ | FILE_WRITE | FILE_BINARY | FILE_SERIAL;
8239 if (fd_info[ fd ].cp != NULL)
8241 error ("fd_info[fd = %d] is already in use", fd);
8243 fd_info[ fd ].cp = cp;
8244 cp->ovl_read.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
8245 if (cp->ovl_read.hEvent == NULL)
8246 error ("Could not create read event");
8247 cp->ovl_write.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
8248 if (cp->ovl_write.hEvent == NULL)
8249 error ("Could not create write event");
8251 return fd;
8254 /* For serial-process-configure */
8255 void
8256 serial_configure (struct Lisp_Process *p, Lisp_Object contact)
8258 Lisp_Object childp2 = Qnil;
8259 Lisp_Object tem = Qnil;
8260 HANDLE hnd;
8261 DCB dcb;
8262 COMMTIMEOUTS ct;
8263 char summary[4] = "???"; /* This usually becomes "8N1". */
8265 if ((fd_info[ p->outfd ].flags & FILE_SERIAL) == 0)
8266 error ("Not a serial process");
8267 hnd = fd_info[ p->outfd ].hnd;
8269 childp2 = Fcopy_sequence (p->childp);
8271 /* Initialize timeouts for blocking read and blocking write. */
8272 if (!GetCommTimeouts (hnd, &ct))
8273 error ("GetCommTimeouts() failed");
8274 ct.ReadIntervalTimeout = 0;
8275 ct.ReadTotalTimeoutMultiplier = 0;
8276 ct.ReadTotalTimeoutConstant = 0;
8277 ct.WriteTotalTimeoutMultiplier = 0;
8278 ct.WriteTotalTimeoutConstant = 0;
8279 if (!SetCommTimeouts (hnd, &ct))
8280 error ("SetCommTimeouts() failed");
8281 /* Read port attributes and prepare default configuration. */
8282 memset (&dcb, 0, sizeof (dcb));
8283 dcb.DCBlength = sizeof (DCB);
8284 if (!GetCommState (hnd, &dcb))
8285 error ("GetCommState() failed");
8286 dcb.fBinary = TRUE;
8287 dcb.fNull = FALSE;
8288 dcb.fAbortOnError = FALSE;
8289 /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
8290 dcb.ErrorChar = 0;
8291 dcb.EofChar = 0;
8292 dcb.EvtChar = 0;
8294 /* Configure speed. */
8295 if (!NILP (Fplist_member (contact, QCspeed)))
8296 tem = Fplist_get (contact, QCspeed);
8297 else
8298 tem = Fplist_get (p->childp, QCspeed);
8299 CHECK_NUMBER (tem);
8300 dcb.BaudRate = XINT (tem);
8301 childp2 = Fplist_put (childp2, QCspeed, tem);
8303 /* Configure bytesize. */
8304 if (!NILP (Fplist_member (contact, QCbytesize)))
8305 tem = Fplist_get (contact, QCbytesize);
8306 else
8307 tem = Fplist_get (p->childp, QCbytesize);
8308 if (NILP (tem))
8309 tem = make_number (8);
8310 CHECK_NUMBER (tem);
8311 if (XINT (tem) != 7 && XINT (tem) != 8)
8312 error (":bytesize must be nil (8), 7, or 8");
8313 dcb.ByteSize = XINT (tem);
8314 summary[0] = XINT (tem) + '0';
8315 childp2 = Fplist_put (childp2, QCbytesize, tem);
8317 /* Configure parity. */
8318 if (!NILP (Fplist_member (contact, QCparity)))
8319 tem = Fplist_get (contact, QCparity);
8320 else
8321 tem = Fplist_get (p->childp, QCparity);
8322 if (!NILP (tem) && !EQ (tem, Qeven) && !EQ (tem, Qodd))
8323 error (":parity must be nil (no parity), `even', or `odd'");
8324 dcb.fParity = FALSE;
8325 dcb.Parity = NOPARITY;
8326 dcb.fErrorChar = FALSE;
8327 if (NILP (tem))
8329 summary[1] = 'N';
8331 else if (EQ (tem, Qeven))
8333 summary[1] = 'E';
8334 dcb.fParity = TRUE;
8335 dcb.Parity = EVENPARITY;
8336 dcb.fErrorChar = TRUE;
8338 else if (EQ (tem, Qodd))
8340 summary[1] = 'O';
8341 dcb.fParity = TRUE;
8342 dcb.Parity = ODDPARITY;
8343 dcb.fErrorChar = TRUE;
8345 childp2 = Fplist_put (childp2, QCparity, tem);
8347 /* Configure stopbits. */
8348 if (!NILP (Fplist_member (contact, QCstopbits)))
8349 tem = Fplist_get (contact, QCstopbits);
8350 else
8351 tem = Fplist_get (p->childp, QCstopbits);
8352 if (NILP (tem))
8353 tem = make_number (1);
8354 CHECK_NUMBER (tem);
8355 if (XINT (tem) != 1 && XINT (tem) != 2)
8356 error (":stopbits must be nil (1 stopbit), 1, or 2");
8357 summary[2] = XINT (tem) + '0';
8358 if (XINT (tem) == 1)
8359 dcb.StopBits = ONESTOPBIT;
8360 else if (XINT (tem) == 2)
8361 dcb.StopBits = TWOSTOPBITS;
8362 childp2 = Fplist_put (childp2, QCstopbits, tem);
8364 /* Configure flowcontrol. */
8365 if (!NILP (Fplist_member (contact, QCflowcontrol)))
8366 tem = Fplist_get (contact, QCflowcontrol);
8367 else
8368 tem = Fplist_get (p->childp, QCflowcontrol);
8369 if (!NILP (tem) && !EQ (tem, Qhw) && !EQ (tem, Qsw))
8370 error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
8371 dcb.fOutxCtsFlow = FALSE;
8372 dcb.fOutxDsrFlow = FALSE;
8373 dcb.fDtrControl = DTR_CONTROL_DISABLE;
8374 dcb.fDsrSensitivity = FALSE;
8375 dcb.fTXContinueOnXoff = FALSE;
8376 dcb.fOutX = FALSE;
8377 dcb.fInX = FALSE;
8378 dcb.fRtsControl = RTS_CONTROL_DISABLE;
8379 dcb.XonChar = 17; /* Control-Q */
8380 dcb.XoffChar = 19; /* Control-S */
8381 if (NILP (tem))
8383 /* Already configured. */
8385 else if (EQ (tem, Qhw))
8387 dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
8388 dcb.fOutxCtsFlow = TRUE;
8390 else if (EQ (tem, Qsw))
8392 dcb.fOutX = TRUE;
8393 dcb.fInX = TRUE;
8395 childp2 = Fplist_put (childp2, QCflowcontrol, tem);
8397 /* Activate configuration. */
8398 if (!SetCommState (hnd, &dcb))
8399 error ("SetCommState() failed");
8401 childp2 = Fplist_put (childp2, QCsummary, build_string (summary));
8402 pset_childp (p, childp2);
8405 #ifdef HAVE_GNUTLS
8407 ssize_t
8408 emacs_gnutls_pull (gnutls_transport_ptr_t p, void* buf, size_t sz)
8410 int n, err;
8411 SELECT_TYPE fdset;
8412 struct timespec timeout;
8413 struct Lisp_Process *process = (struct Lisp_Process *)p;
8414 int fd = process->infd;
8416 n = sys_read (fd, (char*)buf, sz);
8418 if (n >= 0)
8419 return n;
8421 err = errno;
8423 /* Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
8424 if (err == EWOULDBLOCK)
8425 err = EAGAIN;
8427 emacs_gnutls_transport_set_errno (process->gnutls_state, err);
8429 return -1;
8432 ssize_t
8433 emacs_gnutls_push (gnutls_transport_ptr_t p, const void* buf, size_t sz)
8435 struct Lisp_Process *process = (struct Lisp_Process *)p;
8436 int fd = process->outfd;
8437 ssize_t n = sys_write (fd, buf, sz);
8439 /* 0 or more bytes written means everything went fine. */
8440 if (n >= 0)
8441 return n;
8443 /* Negative bytes written means we got an error in errno.
8444 Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
8445 emacs_gnutls_transport_set_errno (process->gnutls_state,
8446 errno == EWOULDBLOCK ? EAGAIN : errno);
8448 return -1;
8450 #endif /* HAVE_GNUTLS */
8452 /* end of w32.c */