Document image-{next, previous}-file, plus some minor tweak.
[emacs.git] / src / w32.c
blobdde74bfcdd988857e063e751dc7bdbb8f404b572
1 /* Utility and Unix shadow routines for GNU Emacs on the Microsoft Windows API.
3 Copyright (C) 1994-1995, 2000-2013 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
21 Geoff Voelker (voelker@cs.washington.edu) 7-29-94
24 #include <mingw_time.h>
25 #include <stddef.h> /* for offsetof */
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <float.h> /* for DBL_EPSILON */
29 #include <io.h>
30 #include <errno.h>
31 #include <fcntl.h>
32 #include <ctype.h>
33 #include <signal.h>
34 #include <sys/file.h>
35 #include <time.h> /* must be before nt/inc/sys/time.h, for MinGW64 */
36 #include <sys/time.h>
37 #include <sys/utime.h>
38 #include <math.h>
40 /* must include CRT headers *before* config.h */
42 #include <config.h>
43 #include <mbstring.h> /* for _mbspbrk, _mbslwr, _mbsrchr, ... */
45 #undef access
46 #undef chdir
47 #undef chmod
48 #undef creat
49 #undef ctime
50 #undef fopen
51 #undef link
52 #undef mkdir
53 #undef open
54 #undef rename
55 #undef rmdir
56 #undef unlink
58 #undef close
59 #undef dup
60 #undef dup2
61 #undef pipe
62 #undef read
63 #undef write
65 #undef strerror
67 #undef localtime
69 #include "lisp.h"
70 #include "epaths.h" /* for SHELL */
72 #include <pwd.h>
73 #include <grp.h>
75 /* MinGW64 (_W64) defines these in its _mingw.h. */
76 #if defined(__GNUC__) && !defined(_W64)
77 #define _ANONYMOUS_UNION
78 #define _ANONYMOUS_STRUCT
79 #endif
80 #include <windows.h>
81 /* Some versions of compiler define MEMORYSTATUSEX, some don't, so we
82 use a different name to avoid compilation problems. */
83 typedef struct _MEMORY_STATUS_EX {
84 DWORD dwLength;
85 DWORD dwMemoryLoad;
86 DWORDLONG ullTotalPhys;
87 DWORDLONG ullAvailPhys;
88 DWORDLONG ullTotalPageFile;
89 DWORDLONG ullAvailPageFile;
90 DWORDLONG ullTotalVirtual;
91 DWORDLONG ullAvailVirtual;
92 DWORDLONG ullAvailExtendedVirtual;
93 } MEMORY_STATUS_EX,*LPMEMORY_STATUS_EX;
95 /* These are here so that GDB would know about these data types. This
96 allows to attach GDB to Emacs when a fatal exception is triggered
97 and Windows pops up the "application needs to be closed" dialog.
98 At that point, _gnu_exception_handler, the top-level exception
99 handler installed by the MinGW startup code, is somewhere on the
100 call-stack of the main thread, so going to that call frame and
101 looking at the argument to _gnu_exception_handler, which is a
102 PEXCEPTION_POINTERS pointer, can reveal the exception code
103 (excptr->ExceptionRecord->ExceptionCode) and the address where the
104 exception happened (excptr->ExceptionRecord->ExceptionAddress), as
105 well as some additional information specific to the exception. */
106 PEXCEPTION_POINTERS excptr;
107 PEXCEPTION_RECORD excprec;
108 PCONTEXT ctxrec;
110 #include <lmcons.h>
111 #include <shlobj.h>
113 #include <tlhelp32.h>
114 #include <psapi.h>
115 #ifndef _MSC_VER
116 #include <w32api.h>
117 #endif
118 #if _WIN32_WINNT < 0x0500
119 #if !defined (__MINGW32__) || __W32API_MAJOR_VERSION < 3 || (__W32API_MAJOR_VERSION == 3 && __W32API_MINOR_VERSION < 15)
120 /* This either is not in psapi.h or guarded by higher value of
121 _WIN32_WINNT than what we use. w32api supplied with MinGW 3.15
122 defines it in psapi.h */
123 typedef struct _PROCESS_MEMORY_COUNTERS_EX {
124 DWORD cb;
125 DWORD PageFaultCount;
126 SIZE_T PeakWorkingSetSize;
127 SIZE_T WorkingSetSize;
128 SIZE_T QuotaPeakPagedPoolUsage;
129 SIZE_T QuotaPagedPoolUsage;
130 SIZE_T QuotaPeakNonPagedPoolUsage;
131 SIZE_T QuotaNonPagedPoolUsage;
132 SIZE_T PagefileUsage;
133 SIZE_T PeakPagefileUsage;
134 SIZE_T PrivateUsage;
135 } PROCESS_MEMORY_COUNTERS_EX,*PPROCESS_MEMORY_COUNTERS_EX;
136 #endif
137 #endif
139 #include <winioctl.h>
140 #include <aclapi.h>
141 #include <sddl.h>
143 #include <sys/acl.h>
144 #include <acl.h>
146 /* This is not in MinGW's sddl.h (but they are in MSVC headers), so we
147 define them by hand if not already defined. */
148 #ifndef SDDL_REVISION_1
149 #define SDDL_REVISION_1 1
150 #endif /* SDDL_REVISION_1 */
152 #if defined(_MSC_VER) || defined(_W64)
153 /* MSVC and MinGW64 don't provide the definition of
154 REPARSE_DATA_BUFFER and the associated macros, except on ntifs.h,
155 which cannot be included because it triggers conflicts with other
156 Windows API headers. So we define it here by hand. */
158 typedef struct _REPARSE_DATA_BUFFER {
159 ULONG ReparseTag;
160 USHORT ReparseDataLength;
161 USHORT Reserved;
162 union {
163 struct {
164 USHORT SubstituteNameOffset;
165 USHORT SubstituteNameLength;
166 USHORT PrintNameOffset;
167 USHORT PrintNameLength;
168 ULONG Flags;
169 WCHAR PathBuffer[1];
170 } SymbolicLinkReparseBuffer;
171 struct {
172 USHORT SubstituteNameOffset;
173 USHORT SubstituteNameLength;
174 USHORT PrintNameOffset;
175 USHORT PrintNameLength;
176 WCHAR PathBuffer[1];
177 } MountPointReparseBuffer;
178 struct {
179 UCHAR DataBuffer[1];
180 } GenericReparseBuffer;
181 } DUMMYUNIONNAME;
182 } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
184 #ifndef FILE_DEVICE_FILE_SYSTEM
185 #define FILE_DEVICE_FILE_SYSTEM 9
186 #endif
187 #ifndef METHOD_BUFFERED
188 #define METHOD_BUFFERED 0
189 #endif
190 #ifndef FILE_ANY_ACCESS
191 #define FILE_ANY_ACCESS 0x00000000
192 #endif
193 #ifndef CTL_CODE
194 #define CTL_CODE(t,f,m,a) (((t)<<16)|((a)<<14)|((f)<<2)|(m))
195 #endif
196 /* MinGW64 defines FSCTL_GET_REPARSE_POINT on winioctl.h. */
197 #ifndef FSCTL_GET_REPARSE_POINT
198 #define FSCTL_GET_REPARSE_POINT \
199 CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS)
200 #endif
201 #endif
203 /* TCP connection support. */
204 #include <sys/socket.h>
205 #undef socket
206 #undef bind
207 #undef connect
208 #undef htons
209 #undef ntohs
210 #undef inet_addr
211 #undef gethostname
212 #undef gethostbyname
213 #undef getservbyname
214 #undef getpeername
215 #undef shutdown
216 #undef setsockopt
217 #undef listen
218 #undef getsockname
219 #undef accept
220 #undef recvfrom
221 #undef sendto
223 #include <iphlpapi.h> /* should be after winsock2.h */
225 #include "w32.h"
226 #include <dirent.h>
227 #include "w32common.h"
228 #include "w32heap.h"
229 #include "w32select.h"
230 #include "systime.h"
231 #include "dispextern.h" /* for xstrcasecmp */
232 #include "coding.h" /* for Vlocale_coding_system */
234 #include "careadlinkat.h"
235 #include "allocator.h"
237 /* For serial_configure and serial_open. */
238 #include "process.h"
240 typedef HRESULT (WINAPI * ShGetFolderPath_fn)
241 (IN HWND, IN int, IN HANDLE, IN DWORD, OUT char *);
243 Lisp_Object QCloaded_from;
245 void globals_of_w32 (void);
246 static DWORD get_rid (PSID);
247 static int is_symlink (const char *);
248 static char * chase_symlinks (const char *);
249 static int enable_privilege (LPCTSTR, BOOL, TOKEN_PRIVILEGES *);
250 static int restore_privilege (TOKEN_PRIVILEGES *);
251 static BOOL WINAPI revert_to_self (void);
253 static int sys_access (const char *, int);
254 extern void *e_malloc (size_t);
255 extern int sys_select (int, SELECT_TYPE *, SELECT_TYPE *, SELECT_TYPE *,
256 struct timespec *, void *);
257 extern int sys_dup (int);
262 /* Initialization states.
264 WARNING: If you add any more such variables for additional APIs,
265 you MUST add initialization for them to globals_of_w32
266 below. This is because these variables might get set
267 to non-NULL values during dumping, but the dumped Emacs
268 cannot reuse those values, because it could be run on a
269 different version of the OS, where API addresses are
270 different. */
271 static BOOL g_b_init_is_windows_9x;
272 static BOOL g_b_init_open_process_token;
273 static BOOL g_b_init_get_token_information;
274 static BOOL g_b_init_lookup_account_sid;
275 static BOOL g_b_init_get_sid_sub_authority;
276 static BOOL g_b_init_get_sid_sub_authority_count;
277 static BOOL g_b_init_get_security_info;
278 static BOOL g_b_init_get_file_security_w;
279 static BOOL g_b_init_get_file_security_a;
280 static BOOL g_b_init_get_security_descriptor_owner;
281 static BOOL g_b_init_get_security_descriptor_group;
282 static BOOL g_b_init_is_valid_sid;
283 static BOOL g_b_init_create_toolhelp32_snapshot;
284 static BOOL g_b_init_process32_first;
285 static BOOL g_b_init_process32_next;
286 static BOOL g_b_init_open_thread_token;
287 static BOOL g_b_init_impersonate_self;
288 static BOOL g_b_init_revert_to_self;
289 static BOOL g_b_init_get_process_memory_info;
290 static BOOL g_b_init_get_process_working_set_size;
291 static BOOL g_b_init_global_memory_status;
292 static BOOL g_b_init_global_memory_status_ex;
293 static BOOL g_b_init_get_length_sid;
294 static BOOL g_b_init_equal_sid;
295 static BOOL g_b_init_copy_sid;
296 static BOOL g_b_init_get_native_system_info;
297 static BOOL g_b_init_get_system_times;
298 static BOOL g_b_init_create_symbolic_link_w;
299 static BOOL g_b_init_create_symbolic_link_a;
300 static BOOL g_b_init_get_security_descriptor_dacl;
301 static BOOL g_b_init_convert_sd_to_sddl;
302 static BOOL g_b_init_convert_sddl_to_sd;
303 static BOOL g_b_init_is_valid_security_descriptor;
304 static BOOL g_b_init_set_file_security_w;
305 static BOOL g_b_init_set_file_security_a;
306 static BOOL g_b_init_get_adapters_info;
309 BEGIN: Wrapper functions around OpenProcessToken
310 and other functions in advapi32.dll that are only
311 supported in Windows NT / 2k / XP
313 /* ** Function pointer typedefs ** */
314 typedef BOOL (WINAPI * OpenProcessToken_Proc) (
315 HANDLE ProcessHandle,
316 DWORD DesiredAccess,
317 PHANDLE TokenHandle);
318 typedef BOOL (WINAPI * GetTokenInformation_Proc) (
319 HANDLE TokenHandle,
320 TOKEN_INFORMATION_CLASS TokenInformationClass,
321 LPVOID TokenInformation,
322 DWORD TokenInformationLength,
323 PDWORD ReturnLength);
324 typedef BOOL (WINAPI * GetProcessTimes_Proc) (
325 HANDLE process_handle,
326 LPFILETIME creation_time,
327 LPFILETIME exit_time,
328 LPFILETIME kernel_time,
329 LPFILETIME user_time);
331 GetProcessTimes_Proc get_process_times_fn = NULL;
333 #ifdef _UNICODE
334 const char * const LookupAccountSid_Name = "LookupAccountSidW";
335 #else
336 const char * const LookupAccountSid_Name = "LookupAccountSidA";
337 #endif
338 typedef BOOL (WINAPI * LookupAccountSid_Proc) (
339 LPCTSTR lpSystemName,
340 PSID Sid,
341 LPTSTR Name,
342 LPDWORD cbName,
343 LPTSTR DomainName,
344 LPDWORD cbDomainName,
345 PSID_NAME_USE peUse);
346 typedef PDWORD (WINAPI * GetSidSubAuthority_Proc) (
347 PSID pSid,
348 DWORD n);
349 typedef PUCHAR (WINAPI * GetSidSubAuthorityCount_Proc) (
350 PSID pSid);
351 typedef DWORD (WINAPI * GetSecurityInfo_Proc) (
352 HANDLE handle,
353 SE_OBJECT_TYPE ObjectType,
354 SECURITY_INFORMATION SecurityInfo,
355 PSID *ppsidOwner,
356 PSID *ppsidGroup,
357 PACL *ppDacl,
358 PACL *ppSacl,
359 PSECURITY_DESCRIPTOR *ppSecurityDescriptor);
360 typedef BOOL (WINAPI * GetFileSecurityW_Proc) (
361 LPCWSTR lpFileName,
362 SECURITY_INFORMATION RequestedInformation,
363 PSECURITY_DESCRIPTOR pSecurityDescriptor,
364 DWORD nLength,
365 LPDWORD lpnLengthNeeded);
366 typedef BOOL (WINAPI * GetFileSecurityA_Proc) (
367 LPCSTR lpFileName,
368 SECURITY_INFORMATION RequestedInformation,
369 PSECURITY_DESCRIPTOR pSecurityDescriptor,
370 DWORD nLength,
371 LPDWORD lpnLengthNeeded);
372 typedef BOOL (WINAPI *SetFileSecurityW_Proc) (
373 LPCWSTR lpFileName,
374 SECURITY_INFORMATION SecurityInformation,
375 PSECURITY_DESCRIPTOR pSecurityDescriptor);
376 typedef BOOL (WINAPI *SetFileSecurityA_Proc) (
377 LPCSTR lpFileName,
378 SECURITY_INFORMATION SecurityInformation,
379 PSECURITY_DESCRIPTOR pSecurityDescriptor);
380 typedef BOOL (WINAPI * GetSecurityDescriptorOwner_Proc) (
381 PSECURITY_DESCRIPTOR pSecurityDescriptor,
382 PSID *pOwner,
383 LPBOOL lpbOwnerDefaulted);
384 typedef BOOL (WINAPI * GetSecurityDescriptorGroup_Proc) (
385 PSECURITY_DESCRIPTOR pSecurityDescriptor,
386 PSID *pGroup,
387 LPBOOL lpbGroupDefaulted);
388 typedef BOOL (WINAPI *GetSecurityDescriptorDacl_Proc) (
389 PSECURITY_DESCRIPTOR pSecurityDescriptor,
390 LPBOOL lpbDaclPresent,
391 PACL *pDacl,
392 LPBOOL lpbDaclDefaulted);
393 typedef BOOL (WINAPI * IsValidSid_Proc) (
394 PSID sid);
395 typedef HANDLE (WINAPI * CreateToolhelp32Snapshot_Proc) (
396 DWORD dwFlags,
397 DWORD th32ProcessID);
398 typedef BOOL (WINAPI * Process32First_Proc) (
399 HANDLE hSnapshot,
400 LPPROCESSENTRY32 lppe);
401 typedef BOOL (WINAPI * Process32Next_Proc) (
402 HANDLE hSnapshot,
403 LPPROCESSENTRY32 lppe);
404 typedef BOOL (WINAPI * OpenThreadToken_Proc) (
405 HANDLE ThreadHandle,
406 DWORD DesiredAccess,
407 BOOL OpenAsSelf,
408 PHANDLE TokenHandle);
409 typedef BOOL (WINAPI * ImpersonateSelf_Proc) (
410 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel);
411 typedef BOOL (WINAPI * RevertToSelf_Proc) (void);
412 typedef BOOL (WINAPI * GetProcessMemoryInfo_Proc) (
413 HANDLE Process,
414 PPROCESS_MEMORY_COUNTERS ppsmemCounters,
415 DWORD cb);
416 typedef BOOL (WINAPI * GetProcessWorkingSetSize_Proc) (
417 HANDLE hProcess,
418 PSIZE_T lpMinimumWorkingSetSize,
419 PSIZE_T lpMaximumWorkingSetSize);
420 typedef BOOL (WINAPI * GlobalMemoryStatus_Proc) (
421 LPMEMORYSTATUS lpBuffer);
422 typedef BOOL (WINAPI * GlobalMemoryStatusEx_Proc) (
423 LPMEMORY_STATUS_EX lpBuffer);
424 typedef BOOL (WINAPI * CopySid_Proc) (
425 DWORD nDestinationSidLength,
426 PSID pDestinationSid,
427 PSID pSourceSid);
428 typedef BOOL (WINAPI * EqualSid_Proc) (
429 PSID pSid1,
430 PSID pSid2);
431 typedef DWORD (WINAPI * GetLengthSid_Proc) (
432 PSID pSid);
433 typedef void (WINAPI * GetNativeSystemInfo_Proc) (
434 LPSYSTEM_INFO lpSystemInfo);
435 typedef BOOL (WINAPI * GetSystemTimes_Proc) (
436 LPFILETIME lpIdleTime,
437 LPFILETIME lpKernelTime,
438 LPFILETIME lpUserTime);
439 typedef BOOLEAN (WINAPI *CreateSymbolicLinkW_Proc) (
440 LPCWSTR lpSymlinkFileName,
441 LPCWSTR lpTargetFileName,
442 DWORD dwFlags);
443 typedef BOOLEAN (WINAPI *CreateSymbolicLinkA_Proc) (
444 LPCSTR lpSymlinkFileName,
445 LPCSTR lpTargetFileName,
446 DWORD dwFlags);
447 typedef BOOL (WINAPI *ConvertStringSecurityDescriptorToSecurityDescriptor_Proc) (
448 LPCTSTR StringSecurityDescriptor,
449 DWORD StringSDRevision,
450 PSECURITY_DESCRIPTOR *SecurityDescriptor,
451 PULONG SecurityDescriptorSize);
452 typedef BOOL (WINAPI *ConvertSecurityDescriptorToStringSecurityDescriptor_Proc) (
453 PSECURITY_DESCRIPTOR SecurityDescriptor,
454 DWORD RequestedStringSDRevision,
455 SECURITY_INFORMATION SecurityInformation,
456 LPTSTR *StringSecurityDescriptor,
457 PULONG StringSecurityDescriptorLen);
458 typedef BOOL (WINAPI *IsValidSecurityDescriptor_Proc) (PSECURITY_DESCRIPTOR);
459 typedef DWORD (WINAPI *GetAdaptersInfo_Proc) (
460 PIP_ADAPTER_INFO pAdapterInfo,
461 PULONG pOutBufLen);
463 /* ** A utility function ** */
464 static BOOL
465 is_windows_9x (void)
467 static BOOL s_b_ret = 0;
468 OSVERSIONINFO os_ver;
469 if (g_b_init_is_windows_9x == 0)
471 g_b_init_is_windows_9x = 1;
472 ZeroMemory (&os_ver, sizeof (OSVERSIONINFO));
473 os_ver.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
474 if (GetVersionEx (&os_ver))
476 s_b_ret = (os_ver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
479 return s_b_ret;
482 static Lisp_Object ltime (ULONGLONG);
484 /* Get total user and system times for get-internal-run-time.
485 Returns a list of integers if the times are provided by the OS
486 (NT derivatives), otherwise it returns the result of current-time. */
487 Lisp_Object
488 w32_get_internal_run_time (void)
490 if (get_process_times_fn)
492 FILETIME create, exit, kernel, user;
493 HANDLE proc = GetCurrentProcess ();
494 if ((*get_process_times_fn) (proc, &create, &exit, &kernel, &user))
496 LARGE_INTEGER user_int, kernel_int, total;
497 user_int.LowPart = user.dwLowDateTime;
498 user_int.HighPart = user.dwHighDateTime;
499 kernel_int.LowPart = kernel.dwLowDateTime;
500 kernel_int.HighPart = kernel.dwHighDateTime;
501 total.QuadPart = user_int.QuadPart + kernel_int.QuadPart;
502 return ltime (total.QuadPart);
506 return Fcurrent_time ();
509 /* ** The wrapper functions ** */
511 static BOOL WINAPI
512 open_process_token (HANDLE ProcessHandle,
513 DWORD DesiredAccess,
514 PHANDLE TokenHandle)
516 static OpenProcessToken_Proc s_pfn_Open_Process_Token = NULL;
517 HMODULE hm_advapi32 = NULL;
518 if (is_windows_9x () == TRUE)
520 return FALSE;
522 if (g_b_init_open_process_token == 0)
524 g_b_init_open_process_token = 1;
525 hm_advapi32 = LoadLibrary ("Advapi32.dll");
526 s_pfn_Open_Process_Token =
527 (OpenProcessToken_Proc) GetProcAddress (hm_advapi32, "OpenProcessToken");
529 if (s_pfn_Open_Process_Token == NULL)
531 return FALSE;
533 return (
534 s_pfn_Open_Process_Token (
535 ProcessHandle,
536 DesiredAccess,
537 TokenHandle)
541 static BOOL WINAPI
542 get_token_information (HANDLE TokenHandle,
543 TOKEN_INFORMATION_CLASS TokenInformationClass,
544 LPVOID TokenInformation,
545 DWORD TokenInformationLength,
546 PDWORD ReturnLength)
548 static GetTokenInformation_Proc s_pfn_Get_Token_Information = NULL;
549 HMODULE hm_advapi32 = NULL;
550 if (is_windows_9x () == TRUE)
552 return FALSE;
554 if (g_b_init_get_token_information == 0)
556 g_b_init_get_token_information = 1;
557 hm_advapi32 = LoadLibrary ("Advapi32.dll");
558 s_pfn_Get_Token_Information =
559 (GetTokenInformation_Proc) GetProcAddress (hm_advapi32, "GetTokenInformation");
561 if (s_pfn_Get_Token_Information == NULL)
563 return FALSE;
565 return (
566 s_pfn_Get_Token_Information (
567 TokenHandle,
568 TokenInformationClass,
569 TokenInformation,
570 TokenInformationLength,
571 ReturnLength)
575 static BOOL WINAPI
576 lookup_account_sid (LPCTSTR lpSystemName,
577 PSID Sid,
578 LPTSTR Name,
579 LPDWORD cbName,
580 LPTSTR DomainName,
581 LPDWORD cbDomainName,
582 PSID_NAME_USE peUse)
584 static LookupAccountSid_Proc s_pfn_Lookup_Account_Sid = NULL;
585 HMODULE hm_advapi32 = NULL;
586 if (is_windows_9x () == TRUE)
588 return FALSE;
590 if (g_b_init_lookup_account_sid == 0)
592 g_b_init_lookup_account_sid = 1;
593 hm_advapi32 = LoadLibrary ("Advapi32.dll");
594 s_pfn_Lookup_Account_Sid =
595 (LookupAccountSid_Proc) GetProcAddress (hm_advapi32, LookupAccountSid_Name);
597 if (s_pfn_Lookup_Account_Sid == NULL)
599 return FALSE;
601 return (
602 s_pfn_Lookup_Account_Sid (
603 lpSystemName,
604 Sid,
605 Name,
606 cbName,
607 DomainName,
608 cbDomainName,
609 peUse)
613 static PDWORD WINAPI
614 get_sid_sub_authority (PSID pSid, DWORD n)
616 static GetSidSubAuthority_Proc s_pfn_Get_Sid_Sub_Authority = NULL;
617 static DWORD zero = 0U;
618 HMODULE hm_advapi32 = NULL;
619 if (is_windows_9x () == TRUE)
621 return &zero;
623 if (g_b_init_get_sid_sub_authority == 0)
625 g_b_init_get_sid_sub_authority = 1;
626 hm_advapi32 = LoadLibrary ("Advapi32.dll");
627 s_pfn_Get_Sid_Sub_Authority =
628 (GetSidSubAuthority_Proc) GetProcAddress (
629 hm_advapi32, "GetSidSubAuthority");
631 if (s_pfn_Get_Sid_Sub_Authority == NULL)
633 return &zero;
635 return (s_pfn_Get_Sid_Sub_Authority (pSid, n));
638 static PUCHAR WINAPI
639 get_sid_sub_authority_count (PSID pSid)
641 static GetSidSubAuthorityCount_Proc s_pfn_Get_Sid_Sub_Authority_Count = NULL;
642 static UCHAR zero = 0U;
643 HMODULE hm_advapi32 = NULL;
644 if (is_windows_9x () == TRUE)
646 return &zero;
648 if (g_b_init_get_sid_sub_authority_count == 0)
650 g_b_init_get_sid_sub_authority_count = 1;
651 hm_advapi32 = LoadLibrary ("Advapi32.dll");
652 s_pfn_Get_Sid_Sub_Authority_Count =
653 (GetSidSubAuthorityCount_Proc) GetProcAddress (
654 hm_advapi32, "GetSidSubAuthorityCount");
656 if (s_pfn_Get_Sid_Sub_Authority_Count == NULL)
658 return &zero;
660 return (s_pfn_Get_Sid_Sub_Authority_Count (pSid));
663 static DWORD WINAPI
664 get_security_info (HANDLE handle,
665 SE_OBJECT_TYPE ObjectType,
666 SECURITY_INFORMATION SecurityInfo,
667 PSID *ppsidOwner,
668 PSID *ppsidGroup,
669 PACL *ppDacl,
670 PACL *ppSacl,
671 PSECURITY_DESCRIPTOR *ppSecurityDescriptor)
673 static GetSecurityInfo_Proc s_pfn_Get_Security_Info = NULL;
674 HMODULE hm_advapi32 = NULL;
675 if (is_windows_9x () == TRUE)
677 return FALSE;
679 if (g_b_init_get_security_info == 0)
681 g_b_init_get_security_info = 1;
682 hm_advapi32 = LoadLibrary ("Advapi32.dll");
683 s_pfn_Get_Security_Info =
684 (GetSecurityInfo_Proc) GetProcAddress (
685 hm_advapi32, "GetSecurityInfo");
687 if (s_pfn_Get_Security_Info == NULL)
689 return FALSE;
691 return (s_pfn_Get_Security_Info (handle, ObjectType, SecurityInfo,
692 ppsidOwner, ppsidGroup, ppDacl, ppSacl,
693 ppSecurityDescriptor));
696 static BOOL WINAPI
697 get_file_security (const char *lpFileName,
698 SECURITY_INFORMATION RequestedInformation,
699 PSECURITY_DESCRIPTOR pSecurityDescriptor,
700 DWORD nLength,
701 LPDWORD lpnLengthNeeded)
703 static GetFileSecurityA_Proc s_pfn_Get_File_SecurityA = NULL;
704 static GetFileSecurityW_Proc s_pfn_Get_File_SecurityW = NULL;
705 HMODULE hm_advapi32 = NULL;
706 if (is_windows_9x () == TRUE)
708 errno = ENOTSUP;
709 return FALSE;
711 if (w32_unicode_filenames)
713 wchar_t filename_w[MAX_PATH];
715 if (g_b_init_get_file_security_w == 0)
717 g_b_init_get_file_security_w = 1;
718 hm_advapi32 = LoadLibrary ("Advapi32.dll");
719 s_pfn_Get_File_SecurityW =
720 (GetFileSecurityW_Proc) GetProcAddress (hm_advapi32,
721 "GetFileSecurityW");
723 if (s_pfn_Get_File_SecurityW == NULL)
725 errno = ENOTSUP;
726 return FALSE;
728 filename_to_utf16 (lpFileName, filename_w);
729 return (s_pfn_Get_File_SecurityW (filename_w, RequestedInformation,
730 pSecurityDescriptor, nLength,
731 lpnLengthNeeded));
733 else
735 char filename_a[MAX_PATH];
737 if (g_b_init_get_file_security_a == 0)
739 g_b_init_get_file_security_a = 1;
740 hm_advapi32 = LoadLibrary ("Advapi32.dll");
741 s_pfn_Get_File_SecurityA =
742 (GetFileSecurityA_Proc) GetProcAddress (hm_advapi32,
743 "GetFileSecurityA");
745 if (s_pfn_Get_File_SecurityA == NULL)
747 errno = ENOTSUP;
748 return FALSE;
750 filename_to_ansi (lpFileName, filename_a);
751 return (s_pfn_Get_File_SecurityA (filename_a, RequestedInformation,
752 pSecurityDescriptor, nLength,
753 lpnLengthNeeded));
757 static BOOL WINAPI
758 set_file_security (const char *lpFileName,
759 SECURITY_INFORMATION SecurityInformation,
760 PSECURITY_DESCRIPTOR pSecurityDescriptor)
762 static SetFileSecurityW_Proc s_pfn_Set_File_SecurityW = NULL;
763 static SetFileSecurityA_Proc s_pfn_Set_File_SecurityA = NULL;
764 HMODULE hm_advapi32 = NULL;
765 if (is_windows_9x () == TRUE)
767 errno = ENOTSUP;
768 return FALSE;
770 if (w32_unicode_filenames)
772 wchar_t filename_w[MAX_PATH];
774 if (g_b_init_set_file_security_w == 0)
776 g_b_init_set_file_security_w = 1;
777 hm_advapi32 = LoadLibrary ("Advapi32.dll");
778 s_pfn_Set_File_SecurityW =
779 (SetFileSecurityW_Proc) GetProcAddress (hm_advapi32,
780 "SetFileSecurityW");
782 if (s_pfn_Set_File_SecurityW == NULL)
784 errno = ENOTSUP;
785 return FALSE;
787 filename_to_utf16 (lpFileName, filename_w);
788 return (s_pfn_Set_File_SecurityW (filename_w, SecurityInformation,
789 pSecurityDescriptor));
791 else
793 char filename_a[MAX_PATH];
795 if (g_b_init_set_file_security_a == 0)
797 g_b_init_set_file_security_a = 1;
798 hm_advapi32 = LoadLibrary ("Advapi32.dll");
799 s_pfn_Set_File_SecurityA =
800 (SetFileSecurityA_Proc) GetProcAddress (hm_advapi32,
801 "SetFileSecurityA");
803 if (s_pfn_Set_File_SecurityA == NULL)
805 errno = ENOTSUP;
806 return FALSE;
808 filename_to_ansi (lpFileName, filename_a);
809 return (s_pfn_Set_File_SecurityA (filename_a, SecurityInformation,
810 pSecurityDescriptor));
814 static BOOL WINAPI
815 get_security_descriptor_owner (PSECURITY_DESCRIPTOR pSecurityDescriptor,
816 PSID *pOwner,
817 LPBOOL lpbOwnerDefaulted)
819 static GetSecurityDescriptorOwner_Proc s_pfn_Get_Security_Descriptor_Owner = NULL;
820 HMODULE hm_advapi32 = NULL;
821 if (is_windows_9x () == TRUE)
823 errno = ENOTSUP;
824 return FALSE;
826 if (g_b_init_get_security_descriptor_owner == 0)
828 g_b_init_get_security_descriptor_owner = 1;
829 hm_advapi32 = LoadLibrary ("Advapi32.dll");
830 s_pfn_Get_Security_Descriptor_Owner =
831 (GetSecurityDescriptorOwner_Proc) GetProcAddress (
832 hm_advapi32, "GetSecurityDescriptorOwner");
834 if (s_pfn_Get_Security_Descriptor_Owner == NULL)
836 errno = ENOTSUP;
837 return FALSE;
839 return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor, pOwner,
840 lpbOwnerDefaulted));
843 static BOOL WINAPI
844 get_security_descriptor_group (PSECURITY_DESCRIPTOR pSecurityDescriptor,
845 PSID *pGroup,
846 LPBOOL lpbGroupDefaulted)
848 static GetSecurityDescriptorGroup_Proc s_pfn_Get_Security_Descriptor_Group = NULL;
849 HMODULE hm_advapi32 = NULL;
850 if (is_windows_9x () == TRUE)
852 errno = ENOTSUP;
853 return FALSE;
855 if (g_b_init_get_security_descriptor_group == 0)
857 g_b_init_get_security_descriptor_group = 1;
858 hm_advapi32 = LoadLibrary ("Advapi32.dll");
859 s_pfn_Get_Security_Descriptor_Group =
860 (GetSecurityDescriptorGroup_Proc) GetProcAddress (
861 hm_advapi32, "GetSecurityDescriptorGroup");
863 if (s_pfn_Get_Security_Descriptor_Group == NULL)
865 errno = ENOTSUP;
866 return FALSE;
868 return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor, pGroup,
869 lpbGroupDefaulted));
872 static BOOL WINAPI
873 get_security_descriptor_dacl (PSECURITY_DESCRIPTOR pSecurityDescriptor,
874 LPBOOL lpbDaclPresent,
875 PACL *pDacl,
876 LPBOOL lpbDaclDefaulted)
878 static GetSecurityDescriptorDacl_Proc s_pfn_Get_Security_Descriptor_Dacl = NULL;
879 HMODULE hm_advapi32 = NULL;
880 if (is_windows_9x () == TRUE)
882 errno = ENOTSUP;
883 return FALSE;
885 if (g_b_init_get_security_descriptor_dacl == 0)
887 g_b_init_get_security_descriptor_dacl = 1;
888 hm_advapi32 = LoadLibrary ("Advapi32.dll");
889 s_pfn_Get_Security_Descriptor_Dacl =
890 (GetSecurityDescriptorDacl_Proc) GetProcAddress (
891 hm_advapi32, "GetSecurityDescriptorDacl");
893 if (s_pfn_Get_Security_Descriptor_Dacl == NULL)
895 errno = ENOTSUP;
896 return FALSE;
898 return (s_pfn_Get_Security_Descriptor_Dacl (pSecurityDescriptor,
899 lpbDaclPresent, pDacl,
900 lpbDaclDefaulted));
903 static BOOL WINAPI
904 is_valid_sid (PSID sid)
906 static IsValidSid_Proc s_pfn_Is_Valid_Sid = NULL;
907 HMODULE hm_advapi32 = NULL;
908 if (is_windows_9x () == TRUE)
910 return FALSE;
912 if (g_b_init_is_valid_sid == 0)
914 g_b_init_is_valid_sid = 1;
915 hm_advapi32 = LoadLibrary ("Advapi32.dll");
916 s_pfn_Is_Valid_Sid =
917 (IsValidSid_Proc) GetProcAddress (
918 hm_advapi32, "IsValidSid");
920 if (s_pfn_Is_Valid_Sid == NULL)
922 return FALSE;
924 return (s_pfn_Is_Valid_Sid (sid));
927 static BOOL WINAPI
928 equal_sid (PSID sid1, PSID sid2)
930 static EqualSid_Proc s_pfn_Equal_Sid = NULL;
931 HMODULE hm_advapi32 = NULL;
932 if (is_windows_9x () == TRUE)
934 return FALSE;
936 if (g_b_init_equal_sid == 0)
938 g_b_init_equal_sid = 1;
939 hm_advapi32 = LoadLibrary ("Advapi32.dll");
940 s_pfn_Equal_Sid =
941 (EqualSid_Proc) GetProcAddress (
942 hm_advapi32, "EqualSid");
944 if (s_pfn_Equal_Sid == NULL)
946 return FALSE;
948 return (s_pfn_Equal_Sid (sid1, sid2));
951 static DWORD WINAPI
952 get_length_sid (PSID sid)
954 static GetLengthSid_Proc s_pfn_Get_Length_Sid = NULL;
955 HMODULE hm_advapi32 = NULL;
956 if (is_windows_9x () == TRUE)
958 return 0;
960 if (g_b_init_get_length_sid == 0)
962 g_b_init_get_length_sid = 1;
963 hm_advapi32 = LoadLibrary ("Advapi32.dll");
964 s_pfn_Get_Length_Sid =
965 (GetLengthSid_Proc) GetProcAddress (
966 hm_advapi32, "GetLengthSid");
968 if (s_pfn_Get_Length_Sid == NULL)
970 return 0;
972 return (s_pfn_Get_Length_Sid (sid));
975 static BOOL WINAPI
976 copy_sid (DWORD destlen, PSID dest, PSID src)
978 static CopySid_Proc s_pfn_Copy_Sid = NULL;
979 HMODULE hm_advapi32 = NULL;
980 if (is_windows_9x () == TRUE)
982 return FALSE;
984 if (g_b_init_copy_sid == 0)
986 g_b_init_copy_sid = 1;
987 hm_advapi32 = LoadLibrary ("Advapi32.dll");
988 s_pfn_Copy_Sid =
989 (CopySid_Proc) GetProcAddress (
990 hm_advapi32, "CopySid");
992 if (s_pfn_Copy_Sid == NULL)
994 return FALSE;
996 return (s_pfn_Copy_Sid (destlen, dest, src));
1000 END: Wrapper functions around OpenProcessToken
1001 and other functions in advapi32.dll that are only
1002 supported in Windows NT / 2k / XP
1005 static void WINAPI
1006 get_native_system_info (LPSYSTEM_INFO lpSystemInfo)
1008 static GetNativeSystemInfo_Proc s_pfn_Get_Native_System_Info = NULL;
1009 if (is_windows_9x () != TRUE)
1011 if (g_b_init_get_native_system_info == 0)
1013 g_b_init_get_native_system_info = 1;
1014 s_pfn_Get_Native_System_Info =
1015 (GetNativeSystemInfo_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1016 "GetNativeSystemInfo");
1018 if (s_pfn_Get_Native_System_Info != NULL)
1019 s_pfn_Get_Native_System_Info (lpSystemInfo);
1021 else
1022 lpSystemInfo->dwNumberOfProcessors = -1;
1025 static BOOL WINAPI
1026 get_system_times (LPFILETIME lpIdleTime,
1027 LPFILETIME lpKernelTime,
1028 LPFILETIME lpUserTime)
1030 static GetSystemTimes_Proc s_pfn_Get_System_times = NULL;
1031 if (is_windows_9x () == TRUE)
1033 return FALSE;
1035 if (g_b_init_get_system_times == 0)
1037 g_b_init_get_system_times = 1;
1038 s_pfn_Get_System_times =
1039 (GetSystemTimes_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1040 "GetSystemTimes");
1042 if (s_pfn_Get_System_times == NULL)
1043 return FALSE;
1044 return (s_pfn_Get_System_times (lpIdleTime, lpKernelTime, lpUserTime));
1047 static BOOLEAN WINAPI
1048 create_symbolic_link (LPCSTR lpSymlinkFilename,
1049 LPCSTR lpTargetFileName,
1050 DWORD dwFlags)
1052 static CreateSymbolicLinkW_Proc s_pfn_Create_Symbolic_LinkW = NULL;
1053 static CreateSymbolicLinkA_Proc s_pfn_Create_Symbolic_LinkA = NULL;
1054 BOOLEAN retval;
1056 if (is_windows_9x () == TRUE)
1058 errno = ENOSYS;
1059 return 0;
1061 if (w32_unicode_filenames)
1063 wchar_t symfn_w[MAX_PATH], tgtfn_w[MAX_PATH];
1065 if (g_b_init_create_symbolic_link_w == 0)
1067 g_b_init_create_symbolic_link_w = 1;
1068 s_pfn_Create_Symbolic_LinkW =
1069 (CreateSymbolicLinkW_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1070 "CreateSymbolicLinkW");
1072 if (s_pfn_Create_Symbolic_LinkW == NULL)
1074 errno = ENOSYS;
1075 return 0;
1078 filename_to_utf16 (lpSymlinkFilename, symfn_w);
1079 filename_to_utf16 (lpTargetFileName, tgtfn_w);
1080 retval = s_pfn_Create_Symbolic_LinkW (symfn_w, tgtfn_w, dwFlags);
1081 /* If we were denied creation of the symlink, try again after
1082 enabling the SeCreateSymbolicLinkPrivilege for our process. */
1083 if (!retval)
1085 TOKEN_PRIVILEGES priv_current;
1087 if (enable_privilege (SE_CREATE_SYMBOLIC_LINK_NAME, TRUE,
1088 &priv_current))
1090 retval = s_pfn_Create_Symbolic_LinkW (symfn_w, tgtfn_w, dwFlags);
1091 restore_privilege (&priv_current);
1092 revert_to_self ();
1096 else
1098 char symfn_a[MAX_PATH], tgtfn_a[MAX_PATH];
1100 if (g_b_init_create_symbolic_link_a == 0)
1102 g_b_init_create_symbolic_link_a = 1;
1103 s_pfn_Create_Symbolic_LinkA =
1104 (CreateSymbolicLinkA_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1105 "CreateSymbolicLinkA");
1107 if (s_pfn_Create_Symbolic_LinkA == NULL)
1109 errno = ENOSYS;
1110 return 0;
1113 filename_to_ansi (lpSymlinkFilename, symfn_a);
1114 filename_to_ansi (lpTargetFileName, tgtfn_a);
1115 retval = s_pfn_Create_Symbolic_LinkA (symfn_a, tgtfn_a, dwFlags);
1116 /* If we were denied creation of the symlink, try again after
1117 enabling the SeCreateSymbolicLinkPrivilege for our process. */
1118 if (!retval)
1120 TOKEN_PRIVILEGES priv_current;
1122 if (enable_privilege (SE_CREATE_SYMBOLIC_LINK_NAME, TRUE,
1123 &priv_current))
1125 retval = s_pfn_Create_Symbolic_LinkA (symfn_a, tgtfn_a, dwFlags);
1126 restore_privilege (&priv_current);
1127 revert_to_self ();
1131 return retval;
1134 static BOOL WINAPI
1135 is_valid_security_descriptor (PSECURITY_DESCRIPTOR pSecurityDescriptor)
1137 static IsValidSecurityDescriptor_Proc s_pfn_Is_Valid_Security_Descriptor_Proc = NULL;
1139 if (is_windows_9x () == TRUE)
1141 errno = ENOTSUP;
1142 return FALSE;
1145 if (g_b_init_is_valid_security_descriptor == 0)
1147 g_b_init_is_valid_security_descriptor = 1;
1148 s_pfn_Is_Valid_Security_Descriptor_Proc =
1149 (IsValidSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1150 "IsValidSecurityDescriptor");
1152 if (s_pfn_Is_Valid_Security_Descriptor_Proc == NULL)
1154 errno = ENOTSUP;
1155 return FALSE;
1158 return s_pfn_Is_Valid_Security_Descriptor_Proc (pSecurityDescriptor);
1161 static BOOL WINAPI
1162 convert_sd_to_sddl (PSECURITY_DESCRIPTOR SecurityDescriptor,
1163 DWORD RequestedStringSDRevision,
1164 SECURITY_INFORMATION SecurityInformation,
1165 LPTSTR *StringSecurityDescriptor,
1166 PULONG StringSecurityDescriptorLen)
1168 static ConvertSecurityDescriptorToStringSecurityDescriptor_Proc s_pfn_Convert_SD_To_SDDL = NULL;
1169 BOOL retval;
1171 if (is_windows_9x () == TRUE)
1173 errno = ENOTSUP;
1174 return FALSE;
1177 if (g_b_init_convert_sd_to_sddl == 0)
1179 g_b_init_convert_sd_to_sddl = 1;
1180 #ifdef _UNICODE
1181 s_pfn_Convert_SD_To_SDDL =
1182 (ConvertSecurityDescriptorToStringSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1183 "ConvertSecurityDescriptorToStringSecurityDescriptorW");
1184 #else
1185 s_pfn_Convert_SD_To_SDDL =
1186 (ConvertSecurityDescriptorToStringSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1187 "ConvertSecurityDescriptorToStringSecurityDescriptorA");
1188 #endif
1190 if (s_pfn_Convert_SD_To_SDDL == NULL)
1192 errno = ENOTSUP;
1193 return FALSE;
1196 retval = s_pfn_Convert_SD_To_SDDL (SecurityDescriptor,
1197 RequestedStringSDRevision,
1198 SecurityInformation,
1199 StringSecurityDescriptor,
1200 StringSecurityDescriptorLen);
1202 return retval;
1205 static BOOL WINAPI
1206 convert_sddl_to_sd (LPCTSTR StringSecurityDescriptor,
1207 DWORD StringSDRevision,
1208 PSECURITY_DESCRIPTOR *SecurityDescriptor,
1209 PULONG SecurityDescriptorSize)
1211 static ConvertStringSecurityDescriptorToSecurityDescriptor_Proc s_pfn_Convert_SDDL_To_SD = NULL;
1212 BOOL retval;
1214 if (is_windows_9x () == TRUE)
1216 errno = ENOTSUP;
1217 return FALSE;
1220 if (g_b_init_convert_sddl_to_sd == 0)
1222 g_b_init_convert_sddl_to_sd = 1;
1223 #ifdef _UNICODE
1224 s_pfn_Convert_SDDL_To_SD =
1225 (ConvertStringSecurityDescriptorToSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1226 "ConvertStringSecurityDescriptorToSecurityDescriptorW");
1227 #else
1228 s_pfn_Convert_SDDL_To_SD =
1229 (ConvertStringSecurityDescriptorToSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1230 "ConvertStringSecurityDescriptorToSecurityDescriptorA");
1231 #endif
1233 if (s_pfn_Convert_SDDL_To_SD == NULL)
1235 errno = ENOTSUP;
1236 return FALSE;
1239 retval = s_pfn_Convert_SDDL_To_SD (StringSecurityDescriptor,
1240 StringSDRevision,
1241 SecurityDescriptor,
1242 SecurityDescriptorSize);
1244 return retval;
1247 static DWORD WINAPI
1248 get_adapters_info (PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen)
1250 static GetAdaptersInfo_Proc s_pfn_Get_Adapters_Info = NULL;
1251 HMODULE hm_iphlpapi = NULL;
1253 if (is_windows_9x () == TRUE)
1254 return ERROR_NOT_SUPPORTED;
1256 if (g_b_init_get_adapters_info == 0)
1258 g_b_init_get_adapters_info = 1;
1259 hm_iphlpapi = LoadLibrary ("Iphlpapi.dll");
1260 if (hm_iphlpapi)
1261 s_pfn_Get_Adapters_Info = (GetAdaptersInfo_Proc)
1262 GetProcAddress (hm_iphlpapi, "GetAdaptersInfo");
1264 if (s_pfn_Get_Adapters_Info == NULL)
1265 return ERROR_NOT_SUPPORTED;
1266 return s_pfn_Get_Adapters_Info (pAdapterInfo, pOutBufLen);
1271 /* Return 1 if P is a valid pointer to an object of size SIZE. Return
1272 0 if P is NOT a valid pointer. Return -1 if we cannot validate P.
1274 This is called from alloc.c:valid_pointer_p. */
1276 w32_valid_pointer_p (void *p, int size)
1278 SIZE_T done;
1279 HANDLE h = OpenProcess (PROCESS_VM_READ, FALSE, GetCurrentProcessId ());
1281 if (h)
1283 unsigned char *buf = alloca (size);
1284 int retval = ReadProcessMemory (h, p, buf, size, &done);
1286 CloseHandle (h);
1287 return retval;
1289 else
1290 return -1;
1295 /* Here's an overview of how the Windows build supports file names
1296 that cannot be encoded by the current system codepage.
1298 From the POV of Lisp and layers of C code above the functions here,
1299 Emacs on Windows pretends that its file names are encoded in UTF-8;
1300 see encode_file and decode_file on coding.c. Any file name that is
1301 passed as a unibyte string to C functions defined here is assumed
1302 to be in UTF-8 encoding. Any file name returned by functions
1303 defined here must be in UTF-8 encoding, with only a few exceptions
1304 reserved for a couple of special cases. (Be sure to use
1305 MAX_UTF8_PATH for char arrays that store UTF-8 encoded file names,
1306 as they can be much longer than MAX_PATH!)
1308 The UTF-8 encoded file names cannot be passed to system APIs, as
1309 Windows does not support that. Therefore, they are converted
1310 either to UTF-16 or to the ANSI codepage, depending on the value of
1311 w32-unicode-filenames, before calling any system APIs or CRT library
1312 functions. The default value of that variable is determined by the
1313 OS on which Emacs runs: nil on Windows 9X and t otherwise, but the
1314 user can change that default (although I don't see why would she
1315 want to).
1317 The 4 functions defined below, filename_to_utf16, filename_to_ansi,
1318 filename_from_utf16, and filename_from_ansi, are the workhorses of
1319 these conversions. They rely on Windows native APIs
1320 MultiByteToWideChar and WideCharToMultiByte; we cannot use
1321 functions from coding.c here, because they allocate memory, which
1322 is a bad idea on the level of libc, which is what the functions
1323 here emulate. (If you worry about performance due to constant
1324 conversion back and forth from UTF-8 to UTF-16, then don't: first,
1325 it was measured to take only a few microseconds on a not-so-fast
1326 machine, and second, that's exactly what the ANSI APIs we used
1327 before do anyway, because they are just thin wrappers around the
1328 Unicode APIs.)
1330 The variables file-name-coding-system and default-file-name-coding-system
1331 still exist, but are actually used only when a file name needs to
1332 be converted to the ANSI codepage. This happens all the time when
1333 w32-unicode-filenames is nil, but can also happen from time to time
1334 when it is t. Otherwise, these variables have no effect on file-name
1335 encoding when w32-unicode-filenames is t; this is similar to
1336 selection-coding-system.
1338 This arrangement works very well, but it has a few gotchas and
1339 limitations:
1341 . Lisp code that encodes or decodes file names manually should
1342 normally use 'utf-8' as the coding-system on Windows,
1343 disregarding file-name-coding-system. This is a somewhat
1344 unpleasant consequence, but it cannot be avoided. Fortunately,
1345 very few Lisp packages need to do that.
1347 More generally, passing to library functions (e.g., fopen or
1348 opendir) file names already encoded in the ANSI codepage is
1349 explicitly *verboten*, as all those functions, as shadowed and
1350 emulated here, assume they will receive UTF-8 encoded file names.
1352 For the same reasons, no CRT function or Win32 API can be called
1353 directly in Emacs sources, without either converting the file
1354 name sfrom UTF-8 to either UTF-16 or ANSI codepage, or going
1355 through some shadowing function defined here.
1357 . Environment variables stored in Vprocess_environment are encoded
1358 in the ANSI codepage, so if getenv/egetenv is used for a variable
1359 whose value is a file name or a list of directories, it needs to
1360 be converted to UTF-8, before it is used as argument to functions
1361 or decoded into a Lisp string.
1363 . File names passed to external libraries, like the image libraries
1364 and GnuTLS, need special handling. These libraries generally
1365 don't support UTF-16 or UTF-8 file names, so they must get file
1366 names encoded in the ANSI codepage. To facilitate using these
1367 libraries with file names that are not encodable in the ANSI
1368 codepage, use the function ansi_encode_filename, which will try
1369 to use the short 8+3 alias of a file name if that file name is
1370 not encodable in the ANSI codepage. See image.c and gnutls.c for
1371 examples of how this should be done.
1373 . Running subprocesses in non-ASCII directories and with non-ASCII
1374 file arguments is limited to the current codepage (even though
1375 Emacs is perfectly capable of finding an executable program file
1376 even in a directory whose name cannot be encoded in the current
1377 codepage). This is because the command-line arguments are
1378 encoded _before_ they get to the w32-specific level, and the
1379 encoding is not known in advance (it doesn't have to be the
1380 current ANSI codepage), so w32proc.c functions cannot re-encode
1381 them in UTF-16. This should be fixed, but will also require
1382 changes in cmdproxy. The current limitation is not terribly bad
1383 anyway, since very few, if any, Windows console programs that are
1384 likely to be invoked by Emacs support UTF-16 encoded command
1385 lines.
1387 . For similar reasons, server.el and emacsclient are also limited
1388 to the current ANSI codepage for now.
1390 . Emacs itself can only handle command-line arguments encoded in
1391 the current codepage.
1393 . Turning on w32-unicode-filename on Windows 9X (if it at all
1394 works) requires UNICOWS.DLL, which is currently loaded only in a
1395 GUI session. */
1399 /* Converting file names from UTF-8 to either UTF-16 or the ANSI
1400 codepage defined by file-name-coding-system. */
1402 /* Current codepage for encoding file names. */
1403 static int file_name_codepage;
1405 /* Produce a Windows ANSI codepage suitable for encoding file names.
1406 Return the information about that codepage in CP_INFO. */
1407 static int
1408 codepage_for_filenames (CPINFO *cp_info)
1410 /* A simple cache to avoid calling GetCPInfo every time we need to
1411 encode/decode a file name. The file-name encoding is not
1412 supposed to be changed too frequently, if ever. */
1413 static Lisp_Object last_file_name_encoding;
1414 static CPINFO cp;
1415 Lisp_Object current_encoding;
1417 current_encoding = Vfile_name_coding_system;
1418 if (NILP (current_encoding))
1419 current_encoding = Vdefault_file_name_coding_system;
1421 if (!EQ (last_file_name_encoding, current_encoding))
1423 /* Default to the current ANSI codepage. */
1424 file_name_codepage = w32_ansi_code_page;
1426 if (NILP (current_encoding))
1428 char *cpname = SDATA (SYMBOL_NAME (current_encoding));
1429 char *cp = NULL, *end;
1430 int cpnum;
1432 if (strncmp (cpname, "cp", 2) == 0)
1433 cp = cpname + 2;
1434 else if (strncmp (cpname, "windows-", 8) == 0)
1435 cp = cpname + 8;
1437 if (cp)
1439 end = cp;
1440 cpnum = strtol (cp, &end, 10);
1441 if (cpnum && *end == '\0' && end - cp >= 2)
1442 file_name_codepage = cpnum;
1446 if (!file_name_codepage)
1447 file_name_codepage = CP_ACP; /* CP_ACP = 0, but let's not assume that */
1449 if (!GetCPInfo (file_name_codepage, &cp))
1451 file_name_codepage = CP_ACP;
1452 if (!GetCPInfo (file_name_codepage, &cp))
1453 emacs_abort ();
1456 if (cp_info)
1457 *cp_info = cp;
1459 return file_name_codepage;
1463 filename_to_utf16 (const char *fn_in, wchar_t *fn_out)
1465 int result = MultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, fn_in, -1,
1466 fn_out, MAX_PATH);
1468 if (!result)
1470 DWORD err = GetLastError ();
1472 switch (err)
1474 case ERROR_INVALID_FLAGS:
1475 case ERROR_INVALID_PARAMETER:
1476 errno = EINVAL;
1477 break;
1478 case ERROR_INSUFFICIENT_BUFFER:
1479 case ERROR_NO_UNICODE_TRANSLATION:
1480 default:
1481 errno = ENOENT;
1482 break;
1484 return -1;
1486 return 0;
1490 filename_from_utf16 (const wchar_t *fn_in, char *fn_out)
1492 int result = WideCharToMultiByte (CP_UTF8, 0, fn_in, -1,
1493 fn_out, MAX_UTF8_PATH, NULL, NULL);
1495 if (!result)
1497 DWORD err = GetLastError ();
1499 switch (err)
1501 case ERROR_INVALID_FLAGS:
1502 case ERROR_INVALID_PARAMETER:
1503 errno = EINVAL;
1504 break;
1505 case ERROR_INSUFFICIENT_BUFFER:
1506 case ERROR_NO_UNICODE_TRANSLATION:
1507 default:
1508 errno = ENOENT;
1509 break;
1511 return -1;
1513 return 0;
1517 filename_to_ansi (const char *fn_in, char *fn_out)
1519 wchar_t fn_utf16[MAX_PATH];
1521 if (filename_to_utf16 (fn_in, fn_utf16) == 0)
1523 int result;
1524 int codepage = codepage_for_filenames (NULL);
1526 result = WideCharToMultiByte (codepage, 0, fn_utf16, -1,
1527 fn_out, MAX_PATH, NULL, NULL);
1528 if (!result)
1530 DWORD err = GetLastError ();
1532 switch (err)
1534 case ERROR_INVALID_FLAGS:
1535 case ERROR_INVALID_PARAMETER:
1536 errno = EINVAL;
1537 break;
1538 case ERROR_INSUFFICIENT_BUFFER:
1539 case ERROR_NO_UNICODE_TRANSLATION:
1540 default:
1541 errno = ENOENT;
1542 break;
1544 return -1;
1546 return 0;
1548 return -1;
1552 filename_from_ansi (const char *fn_in, char *fn_out)
1554 wchar_t fn_utf16[MAX_PATH];
1555 int codepage = codepage_for_filenames (NULL);
1556 int result = MultiByteToWideChar (codepage, MB_ERR_INVALID_CHARS, fn_in, -1,
1557 fn_utf16, MAX_PATH);
1559 if (!result)
1561 DWORD err = GetLastError ();
1563 switch (err)
1565 case ERROR_INVALID_FLAGS:
1566 case ERROR_INVALID_PARAMETER:
1567 errno = EINVAL;
1568 break;
1569 case ERROR_INSUFFICIENT_BUFFER:
1570 case ERROR_NO_UNICODE_TRANSLATION:
1571 default:
1572 errno = ENOENT;
1573 break;
1575 return -1;
1577 return filename_from_utf16 (fn_utf16, fn_out);
1582 /* The directory where we started, in UTF-8. */
1583 static char startup_dir[MAX_UTF8_PATH];
1585 /* Get the current working directory. */
1586 char *
1587 getcwd (char *dir, int dirsize)
1589 if (!dirsize)
1591 errno = EINVAL;
1592 return NULL;
1594 if (dirsize <= strlen (startup_dir))
1596 errno = ERANGE;
1597 return NULL;
1599 #if 0
1600 if (GetCurrentDirectory (MAXPATHLEN, dir) > 0)
1601 return dir;
1602 return NULL;
1603 #else
1604 /* Emacs doesn't actually change directory itself, it stays in the
1605 same directory where it was started. */
1606 strcpy (dir, startup_dir);
1607 return dir;
1608 #endif
1611 /* Emulate getloadavg. */
1613 struct load_sample {
1614 time_t sample_time;
1615 ULONGLONG idle;
1616 ULONGLONG kernel;
1617 ULONGLONG user;
1620 /* Number of processors on this machine. */
1621 static unsigned num_of_processors;
1623 /* We maintain 1-sec samples for the last 16 minutes in a circular buffer. */
1624 static struct load_sample samples[16*60];
1625 static int first_idx = -1, last_idx = -1;
1626 static int max_idx = sizeof (samples) / sizeof (samples[0]);
1628 static int
1629 buf_next (int from)
1631 int next_idx = from + 1;
1633 if (next_idx >= max_idx)
1634 next_idx = 0;
1636 return next_idx;
1639 static int
1640 buf_prev (int from)
1642 int prev_idx = from - 1;
1644 if (prev_idx < 0)
1645 prev_idx = max_idx - 1;
1647 return prev_idx;
1650 static void
1651 sample_system_load (ULONGLONG *idle, ULONGLONG *kernel, ULONGLONG *user)
1653 SYSTEM_INFO sysinfo;
1654 FILETIME ft_idle, ft_user, ft_kernel;
1656 /* Initialize the number of processors on this machine. */
1657 if (num_of_processors <= 0)
1659 get_native_system_info (&sysinfo);
1660 num_of_processors = sysinfo.dwNumberOfProcessors;
1661 if (num_of_processors <= 0)
1663 GetSystemInfo (&sysinfo);
1664 num_of_processors = sysinfo.dwNumberOfProcessors;
1666 if (num_of_processors <= 0)
1667 num_of_processors = 1;
1670 /* TODO: Take into account threads that are ready to run, by
1671 sampling the "\System\Processor Queue Length" performance
1672 counter. The code below accounts only for threads that are
1673 actually running. */
1675 if (get_system_times (&ft_idle, &ft_kernel, &ft_user))
1677 ULARGE_INTEGER uidle, ukernel, uuser;
1679 memcpy (&uidle, &ft_idle, sizeof (ft_idle));
1680 memcpy (&ukernel, &ft_kernel, sizeof (ft_kernel));
1681 memcpy (&uuser, &ft_user, sizeof (ft_user));
1682 *idle = uidle.QuadPart;
1683 *kernel = ukernel.QuadPart;
1684 *user = uuser.QuadPart;
1686 else
1688 *idle = 0;
1689 *kernel = 0;
1690 *user = 0;
1694 /* Produce the load average for a given time interval, using the
1695 samples in the samples[] array. WHICH can be 0, 1, or 2, meaning
1696 1-minute, 5-minute, or 15-minute average, respectively. */
1697 static double
1698 getavg (int which)
1700 double retval = -1.0;
1701 double tdiff;
1702 int idx;
1703 double span = (which == 0 ? 1.0 : (which == 1 ? 5.0 : 15.0)) * 60;
1704 time_t now = samples[last_idx].sample_time;
1706 if (first_idx != last_idx)
1708 for (idx = buf_prev (last_idx); ; idx = buf_prev (idx))
1710 tdiff = difftime (now, samples[idx].sample_time);
1711 if (tdiff >= span - 2*DBL_EPSILON*now)
1713 long double sys =
1714 samples[last_idx].kernel + samples[last_idx].user
1715 - (samples[idx].kernel + samples[idx].user);
1716 long double idl = samples[last_idx].idle - samples[idx].idle;
1718 retval = (1.0 - idl / sys) * num_of_processors;
1719 break;
1721 if (idx == first_idx)
1722 break;
1726 return retval;
1730 getloadavg (double loadavg[], int nelem)
1732 int elem;
1733 ULONGLONG idle, kernel, user;
1734 time_t now = time (NULL);
1736 /* If system time jumped back for some reason, delete all samples
1737 whose time is later than the current wall-clock time. This
1738 prevents load average figures from becoming frozen for prolonged
1739 periods of time, when system time is reset backwards. */
1740 if (last_idx >= 0)
1742 while (difftime (now, samples[last_idx].sample_time) < -1.0)
1744 if (last_idx == first_idx)
1746 first_idx = last_idx = -1;
1747 break;
1749 last_idx = buf_prev (last_idx);
1753 /* Store another sample. We ignore samples that are less than 1 sec
1754 apart. */
1755 if (last_idx < 0
1756 || (difftime (now, samples[last_idx].sample_time)
1757 >= 1.0 - 2*DBL_EPSILON*now))
1759 sample_system_load (&idle, &kernel, &user);
1760 last_idx = buf_next (last_idx);
1761 samples[last_idx].sample_time = now;
1762 samples[last_idx].idle = idle;
1763 samples[last_idx].kernel = kernel;
1764 samples[last_idx].user = user;
1765 /* If the buffer has more that 15 min worth of samples, discard
1766 the old ones. */
1767 if (first_idx == -1)
1768 first_idx = last_idx;
1769 while (first_idx != last_idx
1770 && (difftime (now, samples[first_idx].sample_time)
1771 >= 15.0*60 + 2*DBL_EPSILON*now))
1772 first_idx = buf_next (first_idx);
1775 for (elem = 0; elem < nelem; elem++)
1777 double avg = getavg (elem);
1779 if (avg < 0)
1780 break;
1781 loadavg[elem] = avg;
1784 return elem;
1787 /* Emulate getpwuid, getpwnam and others. */
1789 #define PASSWD_FIELD_SIZE 256
1791 static char dflt_passwd_name[PASSWD_FIELD_SIZE];
1792 static char dflt_passwd_passwd[PASSWD_FIELD_SIZE];
1793 static char dflt_passwd_gecos[PASSWD_FIELD_SIZE];
1794 static char dflt_passwd_dir[MAX_UTF8_PATH];
1795 static char dflt_passwd_shell[MAX_UTF8_PATH];
1797 static struct passwd dflt_passwd =
1799 dflt_passwd_name,
1800 dflt_passwd_passwd,
1804 dflt_passwd_gecos,
1805 dflt_passwd_dir,
1806 dflt_passwd_shell,
1809 static char dflt_group_name[GNLEN+1];
1811 static struct group dflt_group =
1813 /* When group information is not available, we return this as the
1814 group for all files. */
1815 dflt_group_name,
1819 unsigned
1820 getuid (void)
1822 return dflt_passwd.pw_uid;
1825 unsigned
1826 geteuid (void)
1828 /* I could imagine arguing for checking to see whether the user is
1829 in the Administrators group and returning a UID of 0 for that
1830 case, but I don't know how wise that would be in the long run. */
1831 return getuid ();
1834 unsigned
1835 getgid (void)
1837 return dflt_passwd.pw_gid;
1840 unsigned
1841 getegid (void)
1843 return getgid ();
1846 struct passwd *
1847 getpwuid (unsigned uid)
1849 if (uid == dflt_passwd.pw_uid)
1850 return &dflt_passwd;
1851 return NULL;
1854 struct group *
1855 getgrgid (gid_t gid)
1857 return &dflt_group;
1860 struct passwd *
1861 getpwnam (char *name)
1863 struct passwd *pw;
1865 pw = getpwuid (getuid ());
1866 if (!pw)
1867 return pw;
1869 if (xstrcasecmp (name, pw->pw_name))
1870 return NULL;
1872 return pw;
1875 static void
1876 init_user_info (void)
1878 /* Find the user's real name by opening the process token and
1879 looking up the name associated with the user-sid in that token.
1881 Use the relative portion of the identifier authority value from
1882 the user-sid as the user id value (same for group id using the
1883 primary group sid from the process token). */
1885 char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
1886 DWORD ulength = sizeof (uname), dlength = sizeof (domain), needed;
1887 DWORD glength = sizeof (gname);
1888 HANDLE token = NULL;
1889 SID_NAME_USE user_type;
1890 unsigned char *buf = NULL;
1891 DWORD blen = 0;
1892 TOKEN_USER user_token;
1893 TOKEN_PRIMARY_GROUP group_token;
1894 BOOL result;
1896 result = open_process_token (GetCurrentProcess (), TOKEN_QUERY, &token);
1897 if (result)
1899 result = get_token_information (token, TokenUser, NULL, 0, &blen);
1900 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
1902 buf = xmalloc (blen);
1903 result = get_token_information (token, TokenUser,
1904 (LPVOID)buf, blen, &needed);
1905 if (result)
1907 memcpy (&user_token, buf, sizeof (user_token));
1908 result = lookup_account_sid (NULL, user_token.User.Sid,
1909 uname, &ulength,
1910 domain, &dlength, &user_type);
1913 else
1914 result = FALSE;
1916 if (result)
1918 strcpy (dflt_passwd.pw_name, uname);
1919 /* Determine a reasonable uid value. */
1920 if (xstrcasecmp ("administrator", uname) == 0)
1922 dflt_passwd.pw_uid = 500; /* well-known Administrator uid */
1923 dflt_passwd.pw_gid = 513; /* well-known None gid */
1925 else
1927 /* Use the last sub-authority value of the RID, the relative
1928 portion of the SID, as user/group ID. */
1929 dflt_passwd.pw_uid = get_rid (user_token.User.Sid);
1931 /* Get group id and name. */
1932 result = get_token_information (token, TokenPrimaryGroup,
1933 (LPVOID)buf, blen, &needed);
1934 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
1936 buf = xrealloc (buf, blen = needed);
1937 result = get_token_information (token, TokenPrimaryGroup,
1938 (LPVOID)buf, blen, &needed);
1940 if (result)
1942 memcpy (&group_token, buf, sizeof (group_token));
1943 dflt_passwd.pw_gid = get_rid (group_token.PrimaryGroup);
1944 dlength = sizeof (domain);
1945 /* If we can get at the real Primary Group name, use that.
1946 Otherwise, the default group name was already set to
1947 "None" in globals_of_w32. */
1948 if (lookup_account_sid (NULL, group_token.PrimaryGroup,
1949 gname, &glength, NULL, &dlength,
1950 &user_type))
1951 strcpy (dflt_group_name, gname);
1953 else
1954 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
1957 /* If security calls are not supported (presumably because we
1958 are running under Windows 9X), fallback to this: */
1959 else if (GetUserName (uname, &ulength))
1961 strcpy (dflt_passwd.pw_name, uname);
1962 if (xstrcasecmp ("administrator", uname) == 0)
1963 dflt_passwd.pw_uid = 0;
1964 else
1965 dflt_passwd.pw_uid = 123;
1966 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
1968 else
1970 strcpy (dflt_passwd.pw_name, "unknown");
1971 dflt_passwd.pw_uid = 123;
1972 dflt_passwd.pw_gid = 123;
1974 dflt_group.gr_gid = dflt_passwd.pw_gid;
1976 /* Set dir and shell from environment variables. */
1977 if (w32_unicode_filenames)
1979 wchar_t *home = _wgetenv (L"HOME");
1980 wchar_t *shell = _wgetenv (L"SHELL");
1982 /* Ensure HOME and SHELL are defined. */
1983 if (home == NULL)
1984 emacs_abort ();
1985 if (shell == NULL)
1986 emacs_abort ();
1987 filename_from_utf16 (home, dflt_passwd.pw_dir);
1988 filename_from_utf16 (shell, dflt_passwd.pw_shell);
1990 else
1992 char *home = getenv ("HOME");
1993 char *shell = getenv ("SHELL");
1995 if (home == NULL)
1996 emacs_abort ();
1997 if (shell == NULL)
1998 emacs_abort ();
1999 filename_from_ansi (home, dflt_passwd.pw_dir);
2000 filename_from_ansi (shell, dflt_passwd.pw_shell);
2003 xfree (buf);
2004 if (token)
2005 CloseHandle (token);
2009 random (void)
2011 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
2012 return ((rand () << 15) | rand ());
2015 void
2016 srandom (int seed)
2018 srand (seed);
2021 /* Return the maximum length in bytes of a multibyte character
2022 sequence encoded in the current ANSI codepage. This is required to
2023 correctly walk the encoded file names one character at a time. */
2024 static int
2025 max_filename_mbslen (void)
2027 CPINFO cp_info;
2029 codepage_for_filenames (&cp_info);
2030 return cp_info.MaxCharSize;
2033 /* Normalize filename by converting in-place all of its path
2034 separators to the separator specified by PATH_SEP. */
2036 static void
2037 normalize_filename (register char *fp, char path_sep)
2039 char *p2;
2041 /* Always lower-case drive letters a-z, even if the filesystem
2042 preserves case in filenames.
2043 This is so filenames can be compared by string comparison
2044 functions that are case-sensitive. Even case-preserving filesystems
2045 do not distinguish case in drive letters. */
2046 p2 = fp + 1;
2048 if (*p2 == ':' && *fp >= 'A' && *fp <= 'Z')
2050 *fp += 'a' - 'A';
2051 fp += 2;
2054 while (*fp)
2056 if ((*fp == '/' || *fp == '\\') && *fp != path_sep)
2057 *fp = path_sep;
2058 fp++;
2062 /* Destructively turn backslashes into slashes. */
2063 void
2064 dostounix_filename (register char *p)
2066 normalize_filename (p, '/');
2069 /* Destructively turn slashes into backslashes. */
2070 void
2071 unixtodos_filename (register char *p)
2073 normalize_filename (p, '\\');
2076 /* Remove all CR's that are followed by a LF.
2077 (From msdos.c...probably should figure out a way to share it,
2078 although this code isn't going to ever change.) */
2079 static int
2080 crlf_to_lf (register int n, register unsigned char *buf)
2082 unsigned char *np = buf;
2083 unsigned char *startp = buf;
2084 unsigned char *endp = buf + n;
2086 if (n == 0)
2087 return n;
2088 while (buf < endp - 1)
2090 if (*buf == 0x0d)
2092 if (*(++buf) != 0x0a)
2093 *np++ = 0x0d;
2095 else
2096 *np++ = *buf++;
2098 if (buf < endp)
2099 *np++ = *buf++;
2100 return np - startp;
2103 /* Parse the root part of file name, if present. Return length and
2104 optionally store pointer to char after root. */
2105 static int
2106 parse_root (const char * name, const char ** pPath)
2108 const char * start = name;
2110 if (name == NULL)
2111 return 0;
2113 /* find the root name of the volume if given */
2114 if (isalpha (name[0]) && name[1] == ':')
2116 /* skip past drive specifier */
2117 name += 2;
2118 if (IS_DIRECTORY_SEP (name[0]))
2119 name++;
2121 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
2123 int slashes = 2;
2125 name += 2;
2128 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
2129 break;
2130 name++;
2132 while ( *name );
2133 if (IS_DIRECTORY_SEP (name[0]))
2134 name++;
2137 if (pPath)
2138 *pPath = name;
2140 return name - start;
2143 /* Get long base name for name; name is assumed to be absolute. */
2144 static int
2145 get_long_basename (char * name, char * buf, int size)
2147 HANDLE dir_handle = INVALID_HANDLE_VALUE;
2148 char fname_utf8[MAX_UTF8_PATH];
2149 int len = 0;
2150 int cstatus = -1;
2152 /* Must be valid filename, no wild cards or other invalid characters. */
2153 if (strpbrk (name, "*?|<>\""))
2154 return 0;
2156 if (w32_unicode_filenames)
2158 wchar_t fname_utf16[MAX_PATH];
2159 WIN32_FIND_DATAW find_data_wide;
2161 filename_to_utf16 (name, fname_utf16);
2162 dir_handle = FindFirstFileW (fname_utf16, &find_data_wide);
2163 if (dir_handle != INVALID_HANDLE_VALUE)
2164 cstatus = filename_from_utf16 (find_data_wide.cFileName, fname_utf8);
2166 else
2168 char fname_ansi[MAX_PATH];
2169 WIN32_FIND_DATAA find_data_ansi;
2171 filename_to_ansi (name, fname_ansi);
2172 /* If the ANSI name includes ? characters, it is not encodable
2173 in the ANSI codepage. In that case, we deliver the question
2174 marks to the caller; calling FindFirstFileA in this case
2175 could return some unrelated file name in the same
2176 directory. */
2177 if (_mbspbrk (fname_ansi, "?"))
2179 /* Find the basename of fname_ansi. */
2180 char *p = strrchr (fname_ansi, '\\');
2182 if (!p)
2183 p = fname_ansi;
2184 else
2185 p++;
2186 cstatus = filename_from_ansi (p, fname_utf8);
2188 else
2190 dir_handle = FindFirstFileA (fname_ansi, &find_data_ansi);
2191 if (dir_handle != INVALID_HANDLE_VALUE)
2192 cstatus = filename_from_ansi (find_data_ansi.cFileName, fname_utf8);
2196 if (cstatus == 0 && (len = strlen (fname_utf8)) < size)
2197 memcpy (buf, fname_utf8, len + 1);
2198 else
2199 len = 0;
2201 if (dir_handle != INVALID_HANDLE_VALUE)
2202 FindClose (dir_handle);
2204 return len;
2207 /* Get long name for file, if possible (assumed to be absolute). */
2208 BOOL
2209 w32_get_long_filename (char * name, char * buf, int size)
2211 char * o = buf;
2212 char * p;
2213 const char * q;
2214 char full[ MAX_UTF8_PATH ];
2215 int len;
2217 len = strlen (name);
2218 if (len >= MAX_UTF8_PATH)
2219 return FALSE;
2221 /* Use local copy for destructive modification. */
2222 memcpy (full, name, len+1);
2223 unixtodos_filename (full);
2225 /* Copy root part verbatim. */
2226 len = parse_root (full, (const char **)&p);
2227 memcpy (o, full, len);
2228 o += len;
2229 *o = '\0';
2230 size -= len;
2232 while (p != NULL && *p)
2234 q = p;
2235 p = strchr (q, '\\');
2236 if (p) *p = '\0';
2237 len = get_long_basename (full, o, size);
2238 if (len > 0)
2240 o += len;
2241 size -= len;
2242 if (p != NULL)
2244 *p++ = '\\';
2245 if (size < 2)
2246 return FALSE;
2247 *o++ = '\\';
2248 size--;
2249 *o = '\0';
2252 else
2253 return FALSE;
2256 return TRUE;
2259 unsigned int
2260 w32_get_short_filename (char * name, char * buf, int size)
2262 if (w32_unicode_filenames)
2264 wchar_t name_utf16[MAX_PATH], short_name[MAX_PATH];
2265 unsigned int retval;
2267 filename_to_utf16 (name, name_utf16);
2268 retval = GetShortPathNameW (name_utf16, short_name, size);
2269 if (retval && retval < size)
2270 filename_from_utf16 (short_name, buf);
2271 return retval;
2273 else
2275 char name_ansi[MAX_PATH];
2277 filename_to_ansi (name, name_ansi);
2278 return GetShortPathNameA (name_ansi, buf, size);
2282 /* Re-encode FILENAME, a UTF-8 encoded unibyte string, using the
2283 MS-Windows ANSI codepage. If FILENAME includes characters not
2284 supported by the ANSI codepage, return the 8+3 alias of FILENAME,
2285 if it exists. This is needed because the w32 build wants to
2286 support file names outside of the system locale, but image
2287 libraries typically don't support wide (a.k.a. "Unicode") APIs
2288 required for that. */
2290 Lisp_Object
2291 ansi_encode_filename (Lisp_Object filename)
2293 Lisp_Object encoded_filename;
2294 char fname[MAX_PATH];
2296 filename_to_ansi (SSDATA (filename), fname);
2297 if (_mbspbrk (fname, "?"))
2299 char shortname[MAX_PATH];
2301 if (w32_get_short_filename (SDATA (filename), shortname, MAX_PATH))
2303 dostounix_filename (shortname);
2304 encoded_filename = build_string (shortname);
2307 else
2308 encoded_filename = build_unibyte_string (fname);
2309 return encoded_filename;
2312 static int
2313 is_unc_volume (const char *filename)
2315 const char *ptr = filename;
2317 if (!IS_DIRECTORY_SEP (ptr[0]) || !IS_DIRECTORY_SEP (ptr[1]) || !ptr[2])
2318 return 0;
2320 if (strpbrk (ptr + 2, "*?|<>\"\\/"))
2321 return 0;
2323 return 1;
2326 /* Emulate the Posix unsetenv. */
2328 unsetenv (const char *name)
2330 char *var;
2331 size_t name_len;
2332 int retval;
2334 if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
2336 errno = EINVAL;
2337 return -1;
2339 name_len = strlen (name);
2340 /* MS docs says an environment variable cannot be longer than 32K. */
2341 if (name_len > 32767)
2343 errno = ENOMEM;
2344 return 0;
2346 /* It is safe to use 'alloca' with 32K size, since the stack is at
2347 least 2MB, and we set it to 8MB in the link command line. */
2348 var = alloca (name_len + 2);
2349 strncpy (var, name, name_len);
2350 var[name_len++] = '=';
2351 var[name_len] = '\0';
2352 return _putenv (var);
2355 /* MS _putenv doesn't support removing a variable when the argument
2356 does not include the '=' character, so we fix that here. */
2358 sys_putenv (char *str)
2360 const char *const name_end = strchr (str, '=');
2362 if (name_end == NULL)
2364 /* Remove the variable from the environment. */
2365 return unsetenv (str);
2368 return _putenv (str);
2371 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
2373 LPBYTE
2374 w32_get_resource (char *key, LPDWORD lpdwtype)
2376 LPBYTE lpvalue;
2377 HKEY hrootkey = NULL;
2378 DWORD cbData;
2380 /* Check both the current user and the local machine to see if
2381 we have any resources. */
2383 if (RegOpenKeyEx (HKEY_CURRENT_USER, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
2385 lpvalue = NULL;
2387 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
2388 && (lpvalue = xmalloc (cbData)) != NULL
2389 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
2391 RegCloseKey (hrootkey);
2392 return (lpvalue);
2395 xfree (lpvalue);
2397 RegCloseKey (hrootkey);
2400 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
2402 lpvalue = NULL;
2404 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
2405 && (lpvalue = xmalloc (cbData)) != NULL
2406 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
2408 RegCloseKey (hrootkey);
2409 return (lpvalue);
2412 xfree (lpvalue);
2414 RegCloseKey (hrootkey);
2417 return (NULL);
2420 /* The argv[] array holds ANSI-encoded strings, and so this function
2421 works with ANS_encoded strings. */
2422 void
2423 init_environment (char ** argv)
2425 static const char * const tempdirs[] = {
2426 "$TMPDIR", "$TEMP", "$TMP", "c:/"
2429 int i;
2431 const int imax = sizeof (tempdirs) / sizeof (tempdirs[0]);
2433 /* Implementation note: This function explicitly works with ANSI
2434 file names, not with UTF-8 encoded file names. This is because
2435 this function pushes variables into the Emacs's environment, and
2436 the environment variables are always assumed to be in the
2437 locale-specific encoding. Do NOT call any functions that accept
2438 UTF-8 file names from this function! */
2440 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
2441 temporary files and assume "/tmp" if $TMPDIR is unset, which
2442 will break on DOS/Windows. Refuse to work if we cannot find
2443 a directory, not even "c:/", usable for that purpose. */
2444 for (i = 0; i < imax ; i++)
2446 const char *tmp = tempdirs[i];
2448 if (*tmp == '$')
2449 tmp = getenv (tmp + 1);
2450 /* Note that `access' can lie to us if the directory resides on a
2451 read-only filesystem, like CD-ROM or a write-protected floppy.
2452 The only way to be really sure is to actually create a file and
2453 see if it succeeds. But I think that's too much to ask. */
2455 /* MSVCRT's _access crashes with D_OK, so we use our replacement. */
2456 if (tmp && sys_access (tmp, D_OK) == 0)
2458 char * var = alloca (strlen (tmp) + 8);
2459 sprintf (var, "TMPDIR=%s", tmp);
2460 _putenv (strdup (var));
2461 break;
2464 if (i >= imax)
2465 cmd_error_internal
2466 (Fcons (Qerror,
2467 Fcons (build_string ("no usable temporary directories found!!"),
2468 Qnil)),
2469 "While setting TMPDIR: ");
2471 /* Check for environment variables and use registry settings if they
2472 don't exist. Fallback on default values where applicable. */
2474 int i;
2475 LPBYTE lpval;
2476 DWORD dwType;
2477 char locale_name[32];
2478 char default_home[MAX_PATH];
2479 int appdata = 0;
2481 static const struct env_entry
2483 char * name;
2484 char * def_value;
2485 } dflt_envvars[] =
2487 /* If the default value is NULL, we will use the value from the
2488 outside environment or the Registry, but will not push the
2489 variable into the Emacs environment if it is defined neither
2490 in the Registry nor in the outside environment. */
2491 {"HOME", "C:/"},
2492 {"PRELOAD_WINSOCK", NULL},
2493 {"emacs_dir", "C:/emacs"},
2494 {"EMACSLOADPATH", NULL},
2495 {"SHELL", "cmdproxy.exe"}, /* perhaps it is somewhere on PATH */
2496 {"EMACSDATA", NULL},
2497 {"EMACSPATH", NULL},
2498 {"INFOPATH", NULL},
2499 {"EMACSDOC", NULL},
2500 {"TERM", "cmd"},
2501 {"LANG", NULL},
2504 #define N_ENV_VARS sizeof (dflt_envvars)/sizeof (dflt_envvars[0])
2506 /* We need to copy dflt_envvars[] and work on the copy because we
2507 don't want the dumped Emacs to inherit the values of
2508 environment variables we saw during dumping (which could be on
2509 a different system). The defaults above must be left intact. */
2510 struct env_entry env_vars[N_ENV_VARS];
2512 for (i = 0; i < N_ENV_VARS; i++)
2513 env_vars[i] = dflt_envvars[i];
2515 /* For backwards compatibility, check if a .emacs file exists in C:/
2516 If not, then we can try to default to the appdata directory under the
2517 user's profile, which is more likely to be writable. */
2518 if (sys_access ("C:/.emacs", F_OK) != 0)
2520 HRESULT profile_result;
2521 /* Dynamically load ShGetFolderPath, as it won't exist on versions
2522 of Windows 95 and NT4 that have not been updated to include
2523 MSIE 5. */
2524 ShGetFolderPath_fn get_folder_path;
2525 get_folder_path = (ShGetFolderPath_fn)
2526 GetProcAddress (GetModuleHandle ("shell32.dll"), "SHGetFolderPathA");
2528 if (get_folder_path != NULL)
2530 profile_result = get_folder_path (NULL, CSIDL_APPDATA, NULL,
2531 0, default_home);
2533 /* If we can't get the appdata dir, revert to old behavior. */
2534 if (profile_result == S_OK)
2536 env_vars[0].def_value = default_home;
2537 appdata = 1;
2542 /* Get default locale info and use it for LANG. */
2543 if (GetLocaleInfo (LOCALE_USER_DEFAULT,
2544 LOCALE_SABBREVLANGNAME | LOCALE_USE_CP_ACP,
2545 locale_name, sizeof (locale_name)))
2547 for (i = 0; i < N_ENV_VARS; i++)
2549 if (strcmp (env_vars[i].name, "LANG") == 0)
2551 env_vars[i].def_value = locale_name;
2552 break;
2557 #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
2559 /* Treat emacs_dir specially: set it unconditionally based on our
2560 location. */
2562 char *p;
2563 char modname[MAX_PATH];
2565 if (!GetModuleFileNameA (NULL, modname, MAX_PATH))
2566 emacs_abort ();
2567 if ((p = _mbsrchr (modname, '\\')) == NULL)
2568 emacs_abort ();
2569 *p = 0;
2571 if ((p = _mbsrchr (modname, '\\'))
2572 /* From bin means installed Emacs, from src means uninstalled. */
2573 && (xstrcasecmp (p, "\\bin") == 0 || xstrcasecmp (p, "\\src") == 0))
2575 char buf[SET_ENV_BUF_SIZE];
2576 int within_build_tree = xstrcasecmp (p, "\\src") == 0;
2578 *p = 0;
2579 for (p = modname; *p; p = CharNext (p))
2580 if (*p == '\\') *p = '/';
2582 _snprintf (buf, sizeof (buf)-1, "emacs_dir=%s", modname);
2583 _putenv (strdup (buf));
2584 /* If we are running from the Posix-like build tree, define
2585 SHELL to point to our own cmdproxy. The loop below will
2586 then disregard PATH_EXEC and the default value. */
2587 if (within_build_tree)
2589 _snprintf (buf, sizeof (buf) - 1,
2590 "SHELL=%s/nt/cmdproxy.exe", modname);
2591 _putenv (strdup (buf));
2596 for (i = 0; i < N_ENV_VARS; i++)
2598 if (!getenv (env_vars[i].name))
2600 int dont_free = 0;
2601 char bufc[SET_ENV_BUF_SIZE];
2603 if ((lpval = w32_get_resource (env_vars[i].name, &dwType)) == NULL
2604 /* Also ignore empty environment variables. */
2605 || *lpval == 0)
2607 xfree (lpval);
2608 dont_free = 1;
2609 if (strcmp (env_vars[i].name, "SHELL") == 0)
2611 /* Look for cmdproxy.exe in every directory in
2612 PATH_EXEC. FIXME: This does not find cmdproxy
2613 in nt/ when we run uninstalled. */
2614 char fname[MAX_PATH];
2615 const char *pstart = PATH_EXEC, *pend;
2617 do {
2618 pend = _mbschr (pstart, ';');
2619 if (!pend)
2620 pend = pstart + strlen (pstart);
2621 /* Be defensive against series of ;;; characters. */
2622 if (pend > pstart)
2624 strncpy (fname, pstart, pend - pstart);
2625 fname[pend - pstart] = '/';
2626 strcpy (&fname[pend - pstart + 1], "cmdproxy.exe");
2627 ExpandEnvironmentStrings ((LPSTR) fname, bufc,
2628 sizeof (bufc));
2629 if (sys_access (bufc, F_OK) == 0)
2631 lpval = bufc;
2632 dwType = REG_SZ;
2633 break;
2636 if (*pend)
2637 pstart = pend + 1;
2638 else
2639 pstart = pend;
2640 if (!*pstart)
2642 /* If not found in any directory, use the
2643 default as the last resort. */
2644 lpval = env_vars[i].def_value;
2645 dwType = REG_EXPAND_SZ;
2647 } while (*pstart);
2649 else
2651 lpval = env_vars[i].def_value;
2652 dwType = REG_EXPAND_SZ;
2654 if (strcmp (env_vars[i].name, "HOME") == 0 && !appdata)
2655 Vdelayed_warnings_list
2656 = Fcons (listn (CONSTYPE_HEAP, 2,
2657 intern ("initialization"),
2658 build_string ("Setting HOME to C:\\ by default is deprecated")),
2659 Vdelayed_warnings_list);
2662 if (lpval)
2664 char buf1[SET_ENV_BUF_SIZE], buf2[SET_ENV_BUF_SIZE];
2666 if (dwType == REG_EXPAND_SZ)
2667 ExpandEnvironmentStrings ((LPSTR) lpval, buf1, sizeof (buf1));
2668 else if (dwType == REG_SZ)
2669 strcpy (buf1, lpval);
2670 if (dwType == REG_EXPAND_SZ || dwType == REG_SZ)
2672 _snprintf (buf2, sizeof (buf2)-1, "%s=%s", env_vars[i].name,
2673 buf1);
2674 _putenv (strdup (buf2));
2677 if (!dont_free)
2678 xfree (lpval);
2684 /* Rebuild system configuration to reflect invoking system. */
2685 Vsystem_configuration = build_string (EMACS_CONFIGURATION);
2687 /* Another special case: on NT, the PATH variable is actually named
2688 "Path" although cmd.exe (perhaps NT itself) arranges for
2689 environment variable lookup and setting to be case insensitive.
2690 However, Emacs assumes a fully case sensitive environment, so we
2691 need to change "Path" to "PATH" to match the expectations of
2692 various elisp packages. We do this by the sneaky method of
2693 modifying the string in the C runtime environ entry.
2695 The same applies to COMSPEC. */
2697 char ** envp;
2699 for (envp = environ; *envp; envp++)
2700 if (_strnicmp (*envp, "PATH=", 5) == 0)
2701 memcpy (*envp, "PATH=", 5);
2702 else if (_strnicmp (*envp, "COMSPEC=", 8) == 0)
2703 memcpy (*envp, "COMSPEC=", 8);
2706 /* Remember the initial working directory for getcwd. */
2707 /* FIXME: Do we need to resolve possible symlinks in startup_dir?
2708 Does it matter anywhere in Emacs? */
2709 if (w32_unicode_filenames)
2711 wchar_t wstartup_dir[MAX_PATH];
2713 if (!GetCurrentDirectoryW (MAX_PATH, wstartup_dir))
2714 emacs_abort ();
2715 filename_from_utf16 (wstartup_dir, startup_dir);
2717 else
2719 char astartup_dir[MAX_PATH];
2721 if (!GetCurrentDirectoryA (MAX_PATH, astartup_dir))
2722 emacs_abort ();
2723 filename_from_ansi (astartup_dir, startup_dir);
2727 static char modname[MAX_PATH];
2729 if (!GetModuleFileNameA (NULL, modname, MAX_PATH))
2730 emacs_abort ();
2731 argv[0] = modname;
2734 /* Determine if there is a middle mouse button, to allow parse_button
2735 to decide whether right mouse events should be mouse-2 or
2736 mouse-3. */
2737 w32_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);
2739 init_user_info ();
2742 /* Called from expand-file-name when default-directory is not a string. */
2744 char *
2745 emacs_root_dir (void)
2747 static char root_dir[MAX_UTF8_PATH];
2748 const char *p;
2750 p = getenv ("emacs_dir");
2751 if (p == NULL)
2752 emacs_abort ();
2753 filename_from_ansi (p, root_dir);
2754 root_dir[parse_root (root_dir, NULL)] = '\0';
2755 dostounix_filename (root_dir);
2756 return root_dir;
2759 #include <sys/timeb.h>
2761 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
2763 gettimeofday (struct timeval *__restrict tv, struct timezone *__restrict tz)
2765 struct _timeb tb;
2766 _ftime (&tb);
2768 tv->tv_sec = tb.time;
2769 tv->tv_usec = tb.millitm * 1000L;
2770 /* Implementation note: _ftime sometimes doesn't update the dstflag
2771 according to the new timezone when the system timezone is
2772 changed. We could fix that by using GetSystemTime and
2773 GetTimeZoneInformation, but that doesn't seem necessary, since
2774 Emacs always calls gettimeofday with the 2nd argument NULL (see
2775 current_emacs_time). */
2776 if (tz)
2778 tz->tz_minuteswest = tb.timezone; /* minutes west of Greenwich */
2779 tz->tz_dsttime = tb.dstflag; /* type of dst correction */
2781 return 0;
2784 /* Emulate fdutimens. */
2786 /* Set the access and modification time stamps of FD (a.k.a. FILE) to be
2787 TIMESPEC[0] and TIMESPEC[1], respectively.
2788 FD must be either negative -- in which case it is ignored --
2789 or a file descriptor that is open on FILE.
2790 If FD is nonnegative, then FILE can be NULL, which means
2791 use just futimes instead of utimes.
2792 If TIMESPEC is null, FAIL.
2793 Return 0 on success, -1 (setting errno) on failure. */
2796 fdutimens (int fd, char const *file, struct timespec const timespec[2])
2798 if (!timespec)
2800 errno = ENOSYS;
2801 return -1;
2803 if (fd < 0 && !file)
2805 errno = EBADF;
2806 return -1;
2808 /* _futime's prototype defines 2nd arg as having the type 'struct
2809 _utimbuf', while utime needs to accept 'struct utimbuf' for
2810 compatibility with Posix. So we need to use 2 different (but
2811 equivalent) types to avoid compiler warnings, sigh. */
2812 if (fd >= 0)
2814 struct _utimbuf _ut;
2816 _ut.actime = timespec[0].tv_sec;
2817 _ut.modtime = timespec[1].tv_sec;
2818 return _futime (fd, &_ut);
2820 else
2822 struct utimbuf ut;
2824 ut.actime = timespec[0].tv_sec;
2825 ut.modtime = timespec[1].tv_sec;
2826 /* Call 'utime', which is implemented below, not the MS library
2827 function, which fails on directories. */
2828 return utime (file, &ut);
2833 /* ------------------------------------------------------------------------- */
2834 /* IO support and wrapper functions for the Windows API. */
2835 /* ------------------------------------------------------------------------- */
2837 /* Place a wrapper around the MSVC version of ctime. It returns NULL
2838 on network directories, so we handle that case here.
2839 (Ulrich Leodolter, 1/11/95). */
2840 char *
2841 sys_ctime (const time_t *t)
2843 char *str = (char *) ctime (t);
2844 return (str ? str : "Sun Jan 01 00:00:00 1970");
2847 /* Emulate sleep...we could have done this with a define, but that
2848 would necessitate including windows.h in the files that used it.
2849 This is much easier. */
2850 void
2851 sys_sleep (int seconds)
2853 Sleep (seconds * 1000);
2856 /* Internal MSVC functions for low-level descriptor munging */
2857 extern int __cdecl _set_osfhnd (int fd, long h);
2858 extern int __cdecl _free_osfhnd (int fd);
2860 /* parallel array of private info on file handles */
2861 filedesc fd_info [ MAXDESC ];
2863 typedef struct volume_info_data {
2864 struct volume_info_data * next;
2866 /* time when info was obtained */
2867 DWORD timestamp;
2869 /* actual volume info */
2870 char * root_dir;
2871 DWORD serialnum;
2872 DWORD maxcomp;
2873 DWORD flags;
2874 char * name;
2875 char * type;
2876 } volume_info_data;
2878 /* Global referenced by various functions. */
2879 static volume_info_data volume_info;
2881 /* Vector to indicate which drives are local and fixed (for which cached
2882 data never expires). */
2883 static BOOL fixed_drives[26];
2885 /* Consider cached volume information to be stale if older than 10s,
2886 at least for non-local drives. Info for fixed drives is never stale. */
2887 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
2888 #define VOLINFO_STILL_VALID( root_dir, info ) \
2889 ( ( isalpha (root_dir[0]) && \
2890 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
2891 || GetTickCount () - info->timestamp < 10000 )
2893 /* Cache support functions. */
2895 /* Simple linked list with linear search is sufficient. */
2896 static volume_info_data *volume_cache = NULL;
2898 static volume_info_data *
2899 lookup_volume_info (char * root_dir)
2901 volume_info_data * info;
2903 for (info = volume_cache; info; info = info->next)
2904 if (xstrcasecmp (info->root_dir, root_dir) == 0)
2905 break;
2906 return info;
2909 static void
2910 add_volume_info (char * root_dir, volume_info_data * info)
2912 info->root_dir = xstrdup (root_dir);
2913 unixtodos_filename (info->root_dir);
2914 info->next = volume_cache;
2915 volume_cache = info;
2919 /* Wrapper for GetVolumeInformation, which uses caching to avoid
2920 performance penalty (~2ms on 486 for local drives, 7.5ms for local
2921 cdrom drive, ~5-10ms or more for remote drives on LAN). */
2922 static volume_info_data *
2923 GetCachedVolumeInformation (char * root_dir)
2925 volume_info_data * info;
2926 char default_root[ MAX_UTF8_PATH ];
2927 char name[MAX_PATH+1];
2928 char type[MAX_PATH+1];
2930 /* NULL for root_dir means use root from current directory. */
2931 if (root_dir == NULL)
2933 if (w32_unicode_filenames)
2935 wchar_t curdirw[MAX_PATH];
2937 if (GetCurrentDirectoryW (MAX_PATH, curdirw) == 0)
2938 return NULL;
2939 filename_from_utf16 (curdirw, default_root);
2941 else
2943 char curdira[MAX_PATH];
2945 if (GetCurrentDirectoryA (MAX_PATH, curdira) == 0)
2946 return NULL;
2947 filename_from_ansi (curdira, default_root);
2949 parse_root (default_root, (const char **)&root_dir);
2950 *root_dir = 0;
2951 root_dir = default_root;
2954 /* Local fixed drives can be cached permanently. Removable drives
2955 cannot be cached permanently, since the volume name and serial
2956 number (if nothing else) can change. Remote drives should be
2957 treated as if they are removable, since there is no sure way to
2958 tell whether they are or not. Also, the UNC association of drive
2959 letters mapped to remote volumes can be changed at any time (even
2960 by other processes) without notice.
2962 As a compromise, so we can benefit from caching info for remote
2963 volumes, we use a simple expiry mechanism to invalidate cache
2964 entries that are more than ten seconds old. */
2966 #if 0
2967 /* No point doing this, because WNetGetConnection is even slower than
2968 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
2969 GetDriveType is about the only call of this type which does not
2970 involve network access, and so is extremely quick). */
2972 /* Map drive letter to UNC if remote. */
2973 if (isalpha (root_dir[0]) && !fixed[DRIVE_INDEX (root_dir[0])])
2975 char remote_name[ 256 ];
2976 char drive[3] = { root_dir[0], ':' };
2978 if (WNetGetConnection (drive, remote_name, sizeof (remote_name))
2979 == NO_ERROR)
2980 /* do something */ ;
2982 #endif
2984 info = lookup_volume_info (root_dir);
2986 if (info == NULL || ! VOLINFO_STILL_VALID (root_dir, info))
2988 DWORD serialnum;
2989 DWORD maxcomp;
2990 DWORD flags;
2992 /* Info is not cached, or is stale. */
2993 if (w32_unicode_filenames)
2995 wchar_t root_w[MAX_PATH];
2996 wchar_t name_w[MAX_PATH+1];
2997 wchar_t type_w[MAX_PATH+1];
2999 filename_to_utf16 (root_dir, root_w);
3000 if (!GetVolumeInformationW (root_w,
3001 name_w, sizeof (name_w),
3002 &serialnum,
3003 &maxcomp,
3004 &flags,
3005 type_w, sizeof (type_w)))
3006 return NULL;
3007 /* Hmm... not really 100% correct, as these 2 are not file
3008 names... */
3009 filename_from_utf16 (name_w, name);
3010 filename_from_utf16 (type_w, type);
3012 else
3014 char root_a[MAX_PATH];
3015 char name_a[MAX_PATH+1];
3016 char type_a[MAX_PATH+1];
3018 filename_to_ansi (root_dir, root_a);
3019 if (!GetVolumeInformationA (root_a,
3020 name_a, sizeof (name_a),
3021 &serialnum,
3022 &maxcomp,
3023 &flags,
3024 type_a, sizeof (type_a)))
3025 return NULL;
3026 filename_from_ansi (name_a, name);
3027 filename_from_ansi (type_a, type);
3030 /* Cache the volume information for future use, overwriting existing
3031 entry if present. */
3032 if (info == NULL)
3034 info = xmalloc (sizeof (volume_info_data));
3035 add_volume_info (root_dir, info);
3037 else
3039 xfree (info->name);
3040 xfree (info->type);
3043 info->name = xstrdup (name);
3044 unixtodos_filename (info->name);
3045 info->serialnum = serialnum;
3046 info->maxcomp = maxcomp;
3047 info->flags = flags;
3048 info->type = xstrdup (type);
3049 info->timestamp = GetTickCount ();
3052 return info;
3055 /* Get information on the volume where NAME is held; set path pointer to
3056 start of pathname in NAME (past UNC header\volume header if present),
3057 if pPath is non-NULL.
3059 Note: if NAME includes symlinks, the information is for the volume
3060 of the symlink, not of its target. That's because, even though
3061 GetVolumeInformation returns information about the symlink target
3062 of its argument, we only pass the root directory to
3063 GetVolumeInformation, not the full NAME. */
3064 static int
3065 get_volume_info (const char * name, const char ** pPath)
3067 char temp[MAX_UTF8_PATH];
3068 char *rootname = NULL; /* default to current volume */
3069 volume_info_data * info;
3070 int root_len = parse_root (name, pPath);
3072 if (name == NULL)
3073 return FALSE;
3075 /* Copy the root name of the volume, if given. */
3076 if (root_len)
3078 strncpy (temp, name, root_len);
3079 temp[root_len] = '\0';
3080 unixtodos_filename (temp);
3081 rootname = temp;
3084 info = GetCachedVolumeInformation (rootname);
3085 if (info != NULL)
3087 /* Set global referenced by other functions. */
3088 volume_info = *info;
3089 return TRUE;
3091 return FALSE;
3094 /* Determine if volume is FAT format (ie. only supports short 8.3
3095 names); also set path pointer to start of pathname in name, if
3096 pPath is non-NULL. */
3097 static int
3098 is_fat_volume (const char * name, const char ** pPath)
3100 if (get_volume_info (name, pPath))
3101 return (volume_info.maxcomp == 12);
3102 return FALSE;
3105 /* Convert all slashes in a filename to backslashes, and map filename
3106 to a valid 8.3 name if necessary. The result is a pointer to a
3107 static buffer, so CAVEAT EMPTOR! */
3108 const char *
3109 map_w32_filename (const char * name, const char ** pPath)
3111 static char shortname[MAX_UTF8_PATH];
3112 char * str = shortname;
3113 char c;
3114 char * path;
3115 const char * save_name = name;
3117 if (strlen (name) >= sizeof (shortname))
3119 /* Return a filename which will cause callers to fail. */
3120 strcpy (shortname, "?");
3121 return shortname;
3124 if (is_fat_volume (name, (const char **)&path)) /* truncate to 8.3 */
3126 register int left = 8; /* maximum number of chars in part */
3127 register int extn = 0; /* extension added? */
3128 register int dots = 2; /* maximum number of dots allowed */
3130 while (name < path)
3131 *str++ = *name++; /* skip past UNC header */
3133 while ((c = *name++))
3135 switch ( c )
3137 case ':':
3138 case '\\':
3139 case '/':
3140 *str++ = (c == ':' ? ':' : '\\');
3141 extn = 0; /* reset extension flags */
3142 dots = 2; /* max 2 dots */
3143 left = 8; /* max length 8 for main part */
3144 break;
3145 case '.':
3146 if ( dots )
3148 /* Convert path components of the form .xxx to _xxx,
3149 but leave . and .. as they are. This allows .emacs
3150 to be read as _emacs, for example. */
3152 if (! *name ||
3153 *name == '.' ||
3154 IS_DIRECTORY_SEP (*name))
3156 *str++ = '.';
3157 dots--;
3159 else
3161 *str++ = '_';
3162 left--;
3163 dots = 0;
3166 else if ( !extn )
3168 *str++ = '.';
3169 extn = 1; /* we've got an extension */
3170 left = 3; /* 3 chars in extension */
3172 else
3174 /* any embedded dots after the first are converted to _ */
3175 *str++ = '_';
3177 break;
3178 case '~':
3179 case '#': /* don't lose these, they're important */
3180 if ( ! left )
3181 str[-1] = c; /* replace last character of part */
3182 /* FALLTHRU */
3183 default:
3184 if ( left && 'A' <= c && c <= 'Z' )
3186 *str++ = tolower (c); /* map to lower case (looks nicer) */
3187 left--;
3188 dots = 0; /* started a path component */
3190 break;
3193 *str = '\0';
3195 else
3197 strcpy (shortname, name);
3198 unixtodos_filename (shortname);
3201 if (pPath)
3202 *pPath = shortname + (path - save_name);
3204 return shortname;
3207 static int
3208 is_exec (const char * name)
3210 char * p = strrchr (name, '.');
3211 return
3212 (p != NULL
3213 && (xstrcasecmp (p, ".exe") == 0 ||
3214 xstrcasecmp (p, ".com") == 0 ||
3215 xstrcasecmp (p, ".bat") == 0 ||
3216 xstrcasecmp (p, ".cmd") == 0));
3219 /* Emulate the Unix directory procedures opendir, closedir, and
3220 readdir. We rename them to sys_* names because some versions of
3221 MinGW startup code call opendir and readdir to glob wildcards, and
3222 the code that calls them doesn't grok UTF-8 encoded file names we
3223 produce in dirent->d_name[]. */
3225 struct dirent dir_static; /* simulated directory contents */
3226 static HANDLE dir_find_handle = INVALID_HANDLE_VALUE;
3227 static int dir_is_fat;
3228 static char dir_pathname[MAX_UTF8_PATH];
3229 static WIN32_FIND_DATAW dir_find_data_w;
3230 static WIN32_FIND_DATAA dir_find_data_a;
3231 #define DIR_FIND_DATA_W 1
3232 #define DIR_FIND_DATA_A 2
3233 static int last_dir_find_data = -1;
3235 /* Support shares on a network resource as subdirectories of a read-only
3236 root directory. */
3237 static HANDLE wnet_enum_handle = INVALID_HANDLE_VALUE;
3238 static HANDLE open_unc_volume (const char *);
3239 static void *read_unc_volume (HANDLE, wchar_t *, char *, int);
3240 static void close_unc_volume (HANDLE);
3242 DIR *
3243 sys_opendir (const char *filename)
3245 DIR *dirp;
3247 /* Opening is done by FindFirstFile. However, a read is inherent to
3248 this operation, so we defer the open until read time. */
3250 if (dir_find_handle != INVALID_HANDLE_VALUE)
3251 return NULL;
3252 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
3253 return NULL;
3255 /* Note: We don't support traversal of UNC volumes via symlinks.
3256 Doing so would mean punishing 99.99% of use cases by resolving
3257 all the possible symlinks in FILENAME, recursively. */
3258 if (is_unc_volume (filename))
3260 wnet_enum_handle = open_unc_volume (filename);
3261 if (wnet_enum_handle == INVALID_HANDLE_VALUE)
3262 return NULL;
3265 if (!(dirp = (DIR *) malloc (sizeof (DIR))))
3266 return NULL;
3268 dirp->dd_fd = 0;
3269 dirp->dd_loc = 0;
3270 dirp->dd_size = 0;
3272 strncpy (dir_pathname, map_w32_filename (filename, NULL), MAX_UTF8_PATH - 1);
3273 dir_pathname[MAX_UTF8_PATH - 1] = '\0';
3274 /* Note: We don't support symlinks to file names on FAT volumes.
3275 Doing so would mean punishing 99.99% of use cases by resolving
3276 all the possible symlinks in FILENAME, recursively. */
3277 dir_is_fat = is_fat_volume (filename, NULL);
3279 return dirp;
3282 void
3283 sys_closedir (DIR *dirp)
3285 /* If we have a find-handle open, close it. */
3286 if (dir_find_handle != INVALID_HANDLE_VALUE)
3288 FindClose (dir_find_handle);
3289 dir_find_handle = INVALID_HANDLE_VALUE;
3291 else if (wnet_enum_handle != INVALID_HANDLE_VALUE)
3293 close_unc_volume (wnet_enum_handle);
3294 wnet_enum_handle = INVALID_HANDLE_VALUE;
3296 xfree ((char *) dirp);
3299 struct dirent *
3300 sys_readdir (DIR *dirp)
3302 int downcase = !NILP (Vw32_downcase_file_names);
3304 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
3306 if (!read_unc_volume (wnet_enum_handle,
3307 dir_find_data_w.cFileName,
3308 dir_find_data_a.cFileName,
3309 MAX_PATH))
3310 return NULL;
3312 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
3313 else if (dir_find_handle == INVALID_HANDLE_VALUE)
3315 char filename[MAX_UTF8_PATH + 2];
3316 int ln;
3318 strcpy (filename, dir_pathname);
3319 ln = strlen (filename) - 1;
3320 if (!IS_DIRECTORY_SEP (filename[ln]))
3321 strcat (filename, "\\");
3322 strcat (filename, "*");
3324 /* Note: No need to resolve symlinks in FILENAME, because
3325 FindFirst opens the directory that is the target of a
3326 symlink. */
3327 if (w32_unicode_filenames)
3329 wchar_t fnw[MAX_PATH];
3331 filename_to_utf16 (filename, fnw);
3332 dir_find_handle = FindFirstFileW (fnw, &dir_find_data_w);
3334 else
3336 char fna[MAX_PATH];
3338 filename_to_ansi (filename, fna);
3339 /* If FILENAME is not representable by the current ANSI
3340 codepage, we don't want FindFirstFileA to interpret the
3341 '?' characters as a wildcard. */
3342 if (_mbspbrk (fna, "?"))
3343 dir_find_handle = INVALID_HANDLE_VALUE;
3344 else
3345 dir_find_handle = FindFirstFileA (fna, &dir_find_data_a);
3348 if (dir_find_handle == INVALID_HANDLE_VALUE)
3349 return NULL;
3351 else if (w32_unicode_filenames)
3353 if (!FindNextFileW (dir_find_handle, &dir_find_data_w))
3354 return NULL;
3356 else
3358 if (!FindNextFileA (dir_find_handle, &dir_find_data_a))
3359 return NULL;
3362 /* Emacs never uses this value, so don't bother making it match
3363 value returned by stat(). */
3364 dir_static.d_ino = 1;
3366 if (w32_unicode_filenames)
3368 if (downcase || dir_is_fat)
3370 wchar_t tem[MAX_PATH];
3372 wcscpy (tem, dir_find_data_w.cFileName);
3373 CharLowerW (tem);
3374 filename_from_utf16 (tem, dir_static.d_name);
3376 else
3377 filename_from_utf16 (dir_find_data_w.cFileName, dir_static.d_name);
3378 last_dir_find_data = DIR_FIND_DATA_W;
3380 else
3382 char tem[MAX_PATH];
3384 /* If the file name in cFileName[] includes `?' characters, it
3385 means the original file name used characters that cannot be
3386 represented by the current ANSI codepage. To avoid total
3387 lossage, retrieve the short 8+3 alias of the long file
3388 name. */
3389 if (_mbspbrk (dir_find_data_a.cFileName, "?"))
3391 strcpy (tem, dir_find_data_a.cAlternateFileName);
3392 /* 8+3 aliases are returned in all caps, which could break
3393 various alists that look at filenames' extensions. */
3394 downcase = 1;
3396 else if (downcase || dir_is_fat)
3397 strcpy (tem, dir_find_data_a.cFileName);
3398 else
3399 filename_from_ansi (dir_find_data_a.cFileName, dir_static.d_name);
3400 if (downcase || dir_is_fat)
3402 _mbslwr (tem);
3403 filename_from_ansi (tem, dir_static.d_name);
3405 last_dir_find_data = DIR_FIND_DATA_A;
3408 dir_static.d_namlen = strlen (dir_static.d_name);
3409 dir_static.d_reclen = sizeof (struct dirent) - MAX_UTF8_PATH + 3 +
3410 dir_static.d_namlen - dir_static.d_namlen % 4;
3412 return &dir_static;
3415 static HANDLE
3416 open_unc_volume (const char *path)
3418 const char *fn = map_w32_filename (path, NULL);
3419 DWORD result;
3420 HANDLE henum;
3422 if (w32_unicode_filenames)
3424 NETRESOURCEW nrw;
3425 wchar_t fnw[MAX_PATH];
3427 nrw.dwScope = RESOURCE_GLOBALNET;
3428 nrw.dwType = RESOURCETYPE_DISK;
3429 nrw.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
3430 nrw.dwUsage = RESOURCEUSAGE_CONTAINER;
3431 nrw.lpLocalName = NULL;
3432 filename_to_utf16 (fn, fnw);
3433 nrw.lpRemoteName = fnw;
3434 nrw.lpComment = NULL;
3435 nrw.lpProvider = NULL;
3437 result = WNetOpenEnumW (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
3438 RESOURCEUSAGE_CONNECTABLE, &nrw, &henum);
3440 else
3442 NETRESOURCEA nra;
3443 char fna[MAX_PATH];
3445 nra.dwScope = RESOURCE_GLOBALNET;
3446 nra.dwType = RESOURCETYPE_DISK;
3447 nra.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
3448 nra.dwUsage = RESOURCEUSAGE_CONTAINER;
3449 nra.lpLocalName = NULL;
3450 filename_to_ansi (fn, fna);
3451 nra.lpRemoteName = fna;
3452 nra.lpComment = NULL;
3453 nra.lpProvider = NULL;
3455 result = WNetOpenEnumA (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
3456 RESOURCEUSAGE_CONNECTABLE, &nra, &henum);
3458 if (result == NO_ERROR)
3459 return henum;
3460 else
3461 return INVALID_HANDLE_VALUE;
3464 static void *
3465 read_unc_volume (HANDLE henum, wchar_t *fname_w, char *fname_a, int size)
3467 DWORD count;
3468 int result;
3469 char *buffer;
3470 DWORD bufsize = 512;
3471 void *retval;
3473 count = 1;
3474 if (w32_unicode_filenames)
3476 wchar_t *ptrw;
3478 bufsize *= 2;
3479 buffer = alloca (bufsize);
3480 result = WNetEnumResourceW (henum, &count, buffer, &bufsize);
3481 if (result != NO_ERROR)
3482 return NULL;
3483 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
3484 ptrw = ((LPNETRESOURCEW) buffer)->lpRemoteName;
3485 ptrw += 2;
3486 while (*ptrw && *ptrw != L'/' && *ptrw != L'\\') ptrw++;
3487 ptrw++;
3488 wcsncpy (fname_w, ptrw, size);
3489 retval = fname_w;
3491 else
3493 int dbcs_p = max_filename_mbslen () > 1;
3494 char *ptra;
3496 buffer = alloca (bufsize);
3497 result = WNetEnumResourceA (henum, &count, buffer, &bufsize);
3498 if (result != NO_ERROR)
3499 return NULL;
3500 ptra = ((LPNETRESOURCEA) buffer)->lpRemoteName;
3501 ptra += 2;
3502 if (!dbcs_p)
3503 while (*ptra && !IS_DIRECTORY_SEP (*ptra)) ptra++;
3504 else
3506 while (*ptra && !IS_DIRECTORY_SEP (*ptra))
3507 ptra = CharNextExA (file_name_codepage, ptra, 0);
3509 ptra++;
3510 strncpy (fname_a, ptra, size);
3511 retval = fname_a;
3514 return retval;
3517 static void
3518 close_unc_volume (HANDLE henum)
3520 if (henum != INVALID_HANDLE_VALUE)
3521 WNetCloseEnum (henum);
3524 static DWORD
3525 unc_volume_file_attributes (const char *path)
3527 HANDLE henum;
3528 DWORD attrs;
3530 henum = open_unc_volume (path);
3531 if (henum == INVALID_HANDLE_VALUE)
3532 return -1;
3534 attrs = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY;
3536 close_unc_volume (henum);
3538 return attrs;
3541 /* Ensure a network connection is authenticated. */
3542 static void
3543 logon_network_drive (const char *path)
3545 char share[MAX_UTF8_PATH];
3546 int n_slashes;
3547 char drive[4];
3548 UINT drvtype;
3549 char *p;
3550 DWORD val;
3552 if (IS_DIRECTORY_SEP (path[0]) && IS_DIRECTORY_SEP (path[1]))
3553 drvtype = DRIVE_REMOTE;
3554 else if (path[0] == '\0' || path[1] != ':')
3555 drvtype = GetDriveType (NULL);
3556 else
3558 drive[0] = path[0];
3559 drive[1] = ':';
3560 drive[2] = '\\';
3561 drive[3] = '\0';
3562 drvtype = GetDriveType (drive);
3565 /* Only logon to networked drives. */
3566 if (drvtype != DRIVE_REMOTE)
3567 return;
3569 n_slashes = 2;
3570 strncpy (share, path, MAX_UTF8_PATH);
3571 /* Truncate to just server and share name. */
3572 for (p = share + 2; *p && p < share + MAX_UTF8_PATH; p++)
3574 if (IS_DIRECTORY_SEP (*p) && ++n_slashes > 3)
3576 *p = '\0';
3577 break;
3581 if (w32_unicode_filenames)
3583 NETRESOURCEW resourcew;
3584 wchar_t share_w[MAX_PATH];
3586 resourcew.dwScope = RESOURCE_GLOBALNET;
3587 resourcew.dwType = RESOURCETYPE_DISK;
3588 resourcew.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
3589 resourcew.dwUsage = RESOURCEUSAGE_CONTAINER;
3590 resourcew.lpLocalName = NULL;
3591 filename_to_utf16 (share, share_w);
3592 resourcew.lpRemoteName = share_w;
3593 resourcew.lpProvider = NULL;
3595 val = WNetAddConnection2W (&resourcew, NULL, NULL, CONNECT_INTERACTIVE);
3597 else
3599 NETRESOURCEA resourcea;
3600 char share_a[MAX_PATH];
3602 resourcea.dwScope = RESOURCE_GLOBALNET;
3603 resourcea.dwType = RESOURCETYPE_DISK;
3604 resourcea.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
3605 resourcea.dwUsage = RESOURCEUSAGE_CONTAINER;
3606 resourcea.lpLocalName = NULL;
3607 filename_to_ansi (share, share_a);
3608 resourcea.lpRemoteName = share_a;
3609 resourcea.lpProvider = NULL;
3611 val = WNetAddConnection2A (&resourcea, NULL, NULL, CONNECT_INTERACTIVE);
3614 switch (val)
3616 case NO_ERROR:
3617 case ERROR_ALREADY_ASSIGNED:
3618 break;
3619 case ERROR_ACCESS_DENIED:
3620 case ERROR_LOGON_FAILURE:
3621 errno = EACCES;
3622 break;
3623 case ERROR_BUSY:
3624 errno = EAGAIN;
3625 break;
3626 case ERROR_BAD_NET_NAME:
3627 case ERROR_NO_NET_OR_BAD_PATH:
3628 case ERROR_NO_NETWORK:
3629 case ERROR_CANCELLED:
3630 default:
3631 errno = ENOENT;
3632 break;
3636 /* Emulate faccessat(2). */
3638 faccessat (int dirfd, const char * path, int mode, int flags)
3640 DWORD attributes;
3642 if (dirfd != AT_FDCWD
3643 && !(IS_DIRECTORY_SEP (path[0])
3644 || IS_DEVICE_SEP (path[1])))
3646 errno = EBADF;
3647 return -1;
3650 /* MSVCRT implementation of 'access' doesn't recognize D_OK, and its
3651 newer versions blow up when passed D_OK. */
3652 path = map_w32_filename (path, NULL);
3653 /* If the last element of PATH is a symlink, we need to resolve it
3654 to get the attributes of its target file. Note: any symlinks in
3655 PATH elements other than the last one are transparently resolved
3656 by GetFileAttributes below. */
3657 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0
3658 && (flags & AT_SYMLINK_NOFOLLOW) == 0)
3659 path = chase_symlinks (path);
3661 if (w32_unicode_filenames)
3663 wchar_t path_w[MAX_PATH];
3665 filename_to_utf16 (path, path_w);
3666 attributes = GetFileAttributesW (path_w);
3668 else
3670 char path_a[MAX_PATH];
3672 filename_to_ansi (path, path_a);
3673 attributes = GetFileAttributesA (path_a);
3676 if (attributes == -1)
3678 DWORD w32err = GetLastError ();
3680 switch (w32err)
3682 case ERROR_INVALID_NAME:
3683 case ERROR_BAD_PATHNAME:
3684 if (is_unc_volume (path))
3686 attributes = unc_volume_file_attributes (path);
3687 if (attributes == -1)
3689 errno = EACCES;
3690 return -1;
3692 break;
3694 /* FALLTHROUGH */
3695 case ERROR_FILE_NOT_FOUND:
3696 case ERROR_BAD_NETPATH:
3697 errno = ENOENT;
3698 break;
3699 default:
3700 errno = EACCES;
3701 break;
3703 return -1;
3705 if ((mode & X_OK) != 0
3706 && !(is_exec (path) || (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0))
3708 errno = EACCES;
3709 return -1;
3711 if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0)
3713 errno = EACCES;
3714 return -1;
3716 if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
3718 errno = EACCES;
3719 return -1;
3721 return 0;
3724 /* A version of 'access' to be used locally with file names in
3725 locale-specific encoding. Does not resolve symlinks and does not
3726 support file names on FAT12 and FAT16 volumes, but that's OK, since
3727 we only invoke this function for files inside the Emacs source or
3728 installation tree, on directories (so any symlinks should have the
3729 directory bit set), and on short file names such as "C:/.emacs". */
3730 static int
3731 sys_access (const char *fname, int mode)
3733 char fname_copy[MAX_PATH], *p;
3734 DWORD attributes;
3736 strcpy (fname_copy, fname);
3737 /* Do the equivalent of unixtodos_filename. */
3738 for (p = fname_copy; *p; p = CharNext (p))
3739 if (*p == '/')
3740 *p = '\\';
3742 if ((attributes = GetFileAttributesA (fname_copy)) == -1)
3744 DWORD w32err = GetLastError ();
3746 switch (w32err)
3748 case ERROR_INVALID_NAME:
3749 case ERROR_BAD_PATHNAME:
3750 case ERROR_FILE_NOT_FOUND:
3751 case ERROR_BAD_NETPATH:
3752 errno = ENOENT;
3753 break;
3754 default:
3755 errno = EACCES;
3756 break;
3758 return -1;
3760 if ((mode & X_OK) != 0
3761 && !(is_exec (fname_copy)
3762 || (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0))
3764 errno = EACCES;
3765 return -1;
3767 if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0)
3769 errno = EACCES;
3770 return -1;
3772 if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
3774 errno = EACCES;
3775 return -1;
3777 return 0;
3780 /* Shadow some MSVC runtime functions to map requests for long filenames
3781 to reasonable short names if necessary. This was originally added to
3782 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
3783 long file names. */
3786 sys_chdir (const char * path)
3788 path = map_w32_filename (path, NULL);
3789 if (w32_unicode_filenames)
3791 wchar_t newdir_w[MAX_PATH];
3793 if (filename_to_utf16 (path, newdir_w) == 0)
3794 return _wchdir (newdir_w);
3795 return -1;
3797 else
3799 char newdir_a[MAX_PATH];
3801 if (filename_to_ansi (path, newdir_a) == 0)
3802 return _chdir (newdir_a);
3803 return -1;
3808 sys_chmod (const char * path, int mode)
3810 path = chase_symlinks (map_w32_filename (path, NULL));
3811 if (w32_unicode_filenames)
3813 wchar_t path_w[MAX_PATH];
3815 filename_to_utf16 (path, path_w);
3816 return _wchmod (path_w, mode);
3818 else
3820 char path_a[MAX_PATH];
3822 filename_to_ansi (path, path_a);
3823 return _chmod (path_a, mode);
3828 sys_creat (const char * path, int mode)
3830 path = map_w32_filename (path, NULL);
3831 if (w32_unicode_filenames)
3833 wchar_t path_w[MAX_PATH];
3835 filename_to_utf16 (path, path_w);
3836 return _wcreat (path_w, mode);
3838 else
3840 char path_a[MAX_PATH];
3842 filename_to_ansi (path, path_a);
3843 return _creat (path_a, mode);
3847 FILE *
3848 sys_fopen (const char * path, const char * mode)
3850 int fd;
3851 int oflag;
3852 const char * mode_save = mode;
3854 /* Force all file handles to be non-inheritable. This is necessary to
3855 ensure child processes don't unwittingly inherit handles that might
3856 prevent future file access. */
3858 if (mode[0] == 'r')
3859 oflag = O_RDONLY;
3860 else if (mode[0] == 'w' || mode[0] == 'a')
3861 oflag = O_WRONLY | O_CREAT | O_TRUNC;
3862 else
3863 return NULL;
3865 /* Only do simplistic option parsing. */
3866 while (*++mode)
3867 if (mode[0] == '+')
3869 oflag &= ~(O_RDONLY | O_WRONLY);
3870 oflag |= O_RDWR;
3872 else if (mode[0] == 'b')
3874 oflag &= ~O_TEXT;
3875 oflag |= O_BINARY;
3877 else if (mode[0] == 't')
3879 oflag &= ~O_BINARY;
3880 oflag |= O_TEXT;
3882 else break;
3884 path = map_w32_filename (path, NULL);
3885 if (w32_unicode_filenames)
3887 wchar_t path_w[MAX_PATH];
3889 filename_to_utf16 (path, path_w);
3890 fd = _wopen (path_w, oflag | _O_NOINHERIT, 0644);
3892 else
3894 char path_a[MAX_PATH];
3896 filename_to_ansi (path, path_a);
3897 fd = _open (path_a, oflag | _O_NOINHERIT, 0644);
3899 if (fd < 0)
3900 return NULL;
3902 return _fdopen (fd, mode_save);
3905 /* This only works on NTFS volumes, but is useful to have. */
3907 sys_link (const char * old, const char * new)
3909 HANDLE fileh;
3910 int result = -1;
3911 char oldname[MAX_UTF8_PATH], newname[MAX_UTF8_PATH];
3912 wchar_t oldname_w[MAX_PATH];
3913 char oldname_a[MAX_PATH];
3915 if (old == NULL || new == NULL)
3917 errno = ENOENT;
3918 return -1;
3921 strcpy (oldname, map_w32_filename (old, NULL));
3922 strcpy (newname, map_w32_filename (new, NULL));
3924 if (w32_unicode_filenames)
3926 filename_to_utf16 (oldname, oldname_w);
3927 fileh = CreateFileW (oldname_w, 0, 0, NULL, OPEN_EXISTING,
3928 FILE_FLAG_BACKUP_SEMANTICS, NULL);
3930 else
3932 filename_to_ansi (oldname, oldname_a);
3933 fileh = CreateFileA (oldname_a, 0, 0, NULL, OPEN_EXISTING,
3934 FILE_FLAG_BACKUP_SEMANTICS, NULL);
3936 if (fileh != INVALID_HANDLE_VALUE)
3938 int wlen;
3940 /* Confusingly, the "alternate" stream name field does not apply
3941 when restoring a hard link, and instead contains the actual
3942 stream data for the link (ie. the name of the link to create).
3943 The WIN32_STREAM_ID structure before the cStreamName field is
3944 the stream header, which is then immediately followed by the
3945 stream data. */
3947 struct {
3948 WIN32_STREAM_ID wid;
3949 WCHAR wbuffer[MAX_PATH]; /* extra space for link name */
3950 } data;
3952 /* We used to pass MB_PRECOMPOSED as the 2nd arg here, but MSDN
3953 indicates that flag is unsupported for CP_UTF8, and OTOH says
3954 it is the default anyway. */
3955 wlen = MultiByteToWideChar (CP_UTF8, 0, newname, -1,
3956 data.wid.cStreamName, MAX_PATH);
3957 if (wlen > 0)
3959 LPVOID context = NULL;
3960 DWORD wbytes = 0;
3962 data.wid.dwStreamId = BACKUP_LINK;
3963 data.wid.dwStreamAttributes = 0;
3964 data.wid.Size.LowPart = wlen * sizeof (WCHAR);
3965 data.wid.Size.HighPart = 0;
3966 data.wid.dwStreamNameSize = 0;
3968 if (BackupWrite (fileh, (LPBYTE)&data,
3969 offsetof (WIN32_STREAM_ID, cStreamName)
3970 + data.wid.Size.LowPart,
3971 &wbytes, FALSE, FALSE, &context)
3972 && BackupWrite (fileh, NULL, 0, &wbytes, TRUE, FALSE, &context))
3974 /* succeeded */
3975 result = 0;
3977 else
3979 DWORD err = GetLastError ();
3980 DWORD attributes;
3982 switch (err)
3984 case ERROR_ACCESS_DENIED:
3985 /* This is what happens when OLDNAME is a directory,
3986 since Windows doesn't support hard links to
3987 directories. Posix says to set errno to EPERM in
3988 that case. */
3989 if (w32_unicode_filenames)
3990 attributes = GetFileAttributesW (oldname_w);
3991 else
3992 attributes = GetFileAttributesA (oldname_a);
3993 if (attributes != -1
3994 && (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
3995 errno = EPERM;
3996 else if (attributes == -1
3997 && is_unc_volume (oldname)
3998 && unc_volume_file_attributes (oldname) != -1)
3999 errno = EPERM;
4000 else
4001 errno = EACCES;
4002 break;
4003 case ERROR_TOO_MANY_LINKS:
4004 errno = EMLINK;
4005 break;
4006 case ERROR_NOT_SAME_DEVICE:
4007 errno = EXDEV;
4008 break;
4009 default:
4010 errno = EINVAL;
4011 break;
4016 CloseHandle (fileh);
4018 else
4019 errno = ENOENT;
4021 return result;
4025 sys_mkdir (const char * path)
4027 path = map_w32_filename (path, NULL);
4029 if (w32_unicode_filenames)
4031 wchar_t path_w[MAX_PATH];
4033 filename_to_utf16 (path, path_w);
4034 return _wmkdir (path_w);
4036 else
4038 char path_a[MAX_PATH];
4040 filename_to_ansi (path, path_a);
4041 return _mkdir (path_a);
4046 sys_open (const char * path, int oflag, int mode)
4048 const char* mpath = map_w32_filename (path, NULL);
4049 int res = -1;
4051 if (w32_unicode_filenames)
4053 wchar_t mpath_w[MAX_PATH];
4055 filename_to_utf16 (mpath, mpath_w);
4056 /* If possible, try to open file without _O_CREAT, to be able to
4057 write to existing hidden and system files. Force all file
4058 handles to be non-inheritable. */
4059 if ((oflag & (_O_CREAT | _O_EXCL)) != (_O_CREAT | _O_EXCL))
4060 res = _wopen (mpath_w, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
4061 if (res < 0)
4062 res = _wopen (mpath_w, oflag | _O_NOINHERIT, mode);
4064 else
4066 char mpath_a[MAX_PATH];
4068 filename_to_ansi (mpath, mpath_a);
4069 if ((oflag & (_O_CREAT | _O_EXCL)) != (_O_CREAT | _O_EXCL))
4070 res = _open (mpath_a, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
4071 if (res < 0)
4072 res = _open (mpath_a, oflag | _O_NOINHERIT, mode);
4075 return res;
4078 /* Implementation of mkostemp for MS-Windows, to avoid race conditions
4079 when using mktemp.
4081 Standard algorithm for generating a temporary file name seems to be
4082 use pid or tid with a letter on the front (in place of the 6 X's)
4083 and cycle through the letters to find a unique name. We extend
4084 that to allow any reasonable character as the first of the 6 X's,
4085 so that the number of simultaneously used temporary files will be
4086 greater. */
4089 mkostemp (char * template, int flags)
4091 char * p;
4092 int i, fd = -1;
4093 unsigned uid = GetCurrentThreadId ();
4094 int save_errno = errno;
4095 static char first_char[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
4097 errno = EINVAL;
4098 if (template == NULL)
4099 return -1;
4101 p = template + strlen (template);
4102 i = 5;
4103 /* replace up to the last 5 X's with uid in decimal */
4104 while (--p >= template && p[0] == 'X' && --i >= 0)
4106 p[0] = '0' + uid % 10;
4107 uid /= 10;
4110 if (i < 0 && p[0] == 'X')
4112 i = 0;
4115 p[0] = first_char[i];
4116 if ((fd = sys_open (template,
4117 flags | _O_CREAT | _O_EXCL | _O_RDWR,
4118 S_IRUSR | S_IWUSR)) >= 0
4119 || errno != EEXIST)
4121 if (fd >= 0)
4122 errno = save_errno;
4123 return fd;
4126 while (++i < sizeof (first_char));
4129 /* Template is badly formed or else we can't generate a unique name. */
4130 return -1;
4134 fchmod (int fd, mode_t mode)
4136 return 0;
4140 sys_rename_replace (const char *oldname, const char *newname, BOOL force)
4142 BOOL result;
4143 char temp[MAX_UTF8_PATH], temp_a[MAX_PATH];;
4144 int newname_dev;
4145 int oldname_dev;
4146 bool have_temp_a = false;
4148 /* MoveFile on Windows 95 doesn't correctly change the short file name
4149 alias in a number of circumstances (it is not easy to predict when
4150 just by looking at oldname and newname, unfortunately). In these
4151 cases, renaming through a temporary name avoids the problem.
4153 A second problem on Windows 95 is that renaming through a temp name when
4154 newname is uppercase fails (the final long name ends up in
4155 lowercase, although the short alias might be uppercase) UNLESS the
4156 long temp name is not 8.3.
4158 So, on Windows 95 we always rename through a temp name, and we make sure
4159 the temp name has a long extension to ensure correct renaming. */
4161 strcpy (temp, map_w32_filename (oldname, NULL));
4163 /* volume_info is set indirectly by map_w32_filename. */
4164 oldname_dev = volume_info.serialnum;
4166 if (os_subtype == OS_9X)
4168 char * o;
4169 char * p;
4170 int i = 0;
4171 char oldname_a[MAX_PATH];
4173 oldname = map_w32_filename (oldname, NULL);
4174 filename_to_ansi (oldname, oldname_a);
4175 filename_to_ansi (temp, temp_a);
4176 if ((o = strrchr (oldname_a, '\\')))
4177 o++;
4178 else
4179 o = (char *) oldname_a;
4181 if ((p = strrchr (temp_a, '\\')))
4182 p++;
4183 else
4184 p = temp_a;
4188 /* Force temp name to require a manufactured 8.3 alias - this
4189 seems to make the second rename work properly. */
4190 sprintf (p, "_.%s.%u", o, i);
4191 i++;
4192 result = rename (oldname_a, temp_a);
4194 /* This loop must surely terminate! */
4195 while (result < 0 && errno == EEXIST);
4196 if (result < 0)
4197 return -1;
4198 have_temp_a = true;
4201 /* If FORCE, emulate Unix behavior - newname is deleted if it already exists
4202 (at least if it is a file; don't do this for directories).
4204 Since we mustn't do this if we are just changing the case of the
4205 file name (we would end up deleting the file we are trying to
4206 rename!), we let rename detect if the destination file already
4207 exists - that way we avoid the possible pitfalls of trying to
4208 determine ourselves whether two names really refer to the same
4209 file, which is not always possible in the general case. (Consider
4210 all the permutations of shared or subst'd drives, etc.) */
4212 newname = map_w32_filename (newname, NULL);
4214 /* volume_info is set indirectly by map_w32_filename. */
4215 newname_dev = volume_info.serialnum;
4217 if (w32_unicode_filenames)
4219 wchar_t temp_w[MAX_PATH], newname_w[MAX_PATH];
4221 filename_to_utf16 (temp, temp_w);
4222 filename_to_utf16 (newname, newname_w);
4223 result = _wrename (temp_w, newname_w);
4224 if (result < 0 && force)
4226 DWORD w32err = GetLastError ();
4228 if (errno == EACCES
4229 && newname_dev != oldname_dev)
4231 /* The implementation of `rename' on Windows does not return
4232 errno = EXDEV when you are moving a directory to a
4233 different storage device (ex. logical disk). It returns
4234 EACCES instead. So here we handle such situations and
4235 return EXDEV. */
4236 DWORD attributes;
4238 if ((attributes = GetFileAttributesW (temp_w)) != -1
4239 && (attributes & FILE_ATTRIBUTE_DIRECTORY))
4240 errno = EXDEV;
4242 else if (errno == EEXIST)
4244 if (_wchmod (newname_w, 0666) != 0)
4245 return result;
4246 if (_wunlink (newname_w) != 0)
4247 return result;
4248 result = _wrename (temp_w, newname_w);
4250 else if (w32err == ERROR_PRIVILEGE_NOT_HELD
4251 && is_symlink (temp))
4253 /* This is Windows prohibiting the user from creating a
4254 symlink in another place, since that requires
4255 privileges. */
4256 errno = EPERM;
4260 else
4262 char newname_a[MAX_PATH];
4264 if (!have_temp_a)
4265 filename_to_ansi (temp, temp_a);
4266 filename_to_ansi (newname, newname_a);
4267 result = rename (temp_a, newname_a);
4268 if (result < 0 && force)
4270 DWORD w32err = GetLastError ();
4272 if (errno == EACCES
4273 && newname_dev != oldname_dev)
4275 DWORD attributes;
4277 if ((attributes = GetFileAttributesA (temp_a)) != -1
4278 && (attributes & FILE_ATTRIBUTE_DIRECTORY))
4279 errno = EXDEV;
4281 else if (errno == EEXIST)
4283 if (_chmod (newname_a, 0666) != 0)
4284 return result;
4285 if (_unlink (newname_a) != 0)
4286 return result;
4287 result = rename (temp_a, newname_a);
4289 else if (w32err == ERROR_PRIVILEGE_NOT_HELD
4290 && is_symlink (temp))
4291 errno = EPERM;
4295 return result;
4299 sys_rename (char const *old, char const *new)
4301 return sys_rename_replace (old, new, TRUE);
4305 sys_rmdir (const char * path)
4307 path = map_w32_filename (path, NULL);
4309 if (w32_unicode_filenames)
4311 wchar_t path_w[MAX_PATH];
4313 filename_to_utf16 (path, path_w);
4314 return _wrmdir (path_w);
4316 else
4318 char path_a[MAX_PATH];
4320 filename_to_ansi (path, path_a);
4321 return _rmdir (path_a);
4326 sys_unlink (const char * path)
4328 path = map_w32_filename (path, NULL);
4330 if (w32_unicode_filenames)
4332 wchar_t path_w[MAX_PATH];
4334 filename_to_utf16 (path, path_w);
4335 /* On Unix, unlink works without write permission. */
4336 _wchmod (path_w, 0666);
4337 return _wunlink (path_w);
4339 else
4341 char path_a[MAX_PATH];
4343 filename_to_ansi (path, path_a);
4344 _chmod (path_a, 0666);
4345 return _unlink (path_a);
4349 static FILETIME utc_base_ft;
4350 static ULONGLONG utc_base; /* In 100ns units */
4351 static int init = 0;
4353 #define FILETIME_TO_U64(result, ft) \
4354 do { \
4355 ULARGE_INTEGER uiTemp; \
4356 uiTemp.LowPart = (ft).dwLowDateTime; \
4357 uiTemp.HighPart = (ft).dwHighDateTime; \
4358 result = uiTemp.QuadPart; \
4359 } while (0)
4361 static void
4362 initialize_utc_base (void)
4364 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
4365 SYSTEMTIME st;
4367 st.wYear = 1970;
4368 st.wMonth = 1;
4369 st.wDay = 1;
4370 st.wHour = 0;
4371 st.wMinute = 0;
4372 st.wSecond = 0;
4373 st.wMilliseconds = 0;
4375 SystemTimeToFileTime (&st, &utc_base_ft);
4376 FILETIME_TO_U64 (utc_base, utc_base_ft);
4379 static time_t
4380 convert_time (FILETIME ft)
4382 ULONGLONG tmp;
4384 if (!init)
4386 initialize_utc_base ();
4387 init = 1;
4390 if (CompareFileTime (&ft, &utc_base_ft) < 0)
4391 return 0;
4393 FILETIME_TO_U64 (tmp, ft);
4394 return (time_t) ((tmp - utc_base) / 10000000L);
4397 static void
4398 convert_from_time_t (time_t time, FILETIME * pft)
4400 ULARGE_INTEGER tmp;
4402 if (!init)
4404 initialize_utc_base ();
4405 init = 1;
4408 /* time in 100ns units since 1-Jan-1601 */
4409 tmp.QuadPart = (ULONGLONG) time * 10000000L + utc_base;
4410 pft->dwHighDateTime = tmp.HighPart;
4411 pft->dwLowDateTime = tmp.LowPart;
4414 static PSECURITY_DESCRIPTOR
4415 get_file_security_desc_by_handle (HANDLE h)
4417 PSECURITY_DESCRIPTOR psd = NULL;
4418 DWORD err;
4419 SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION
4420 | GROUP_SECURITY_INFORMATION /* | DACL_SECURITY_INFORMATION */ ;
4422 err = get_security_info (h, SE_FILE_OBJECT, si,
4423 NULL, NULL, NULL, NULL, &psd);
4424 if (err != ERROR_SUCCESS)
4425 return NULL;
4427 return psd;
4430 static PSECURITY_DESCRIPTOR
4431 get_file_security_desc_by_name (const char *fname)
4433 PSECURITY_DESCRIPTOR psd = NULL;
4434 DWORD sd_len, err;
4435 SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION
4436 | GROUP_SECURITY_INFORMATION /* | DACL_SECURITY_INFORMATION */ ;
4438 if (!get_file_security (fname, si, psd, 0, &sd_len))
4440 err = GetLastError ();
4441 if (err != ERROR_INSUFFICIENT_BUFFER)
4442 return NULL;
4445 psd = xmalloc (sd_len);
4446 if (!get_file_security (fname, si, psd, sd_len, &sd_len))
4448 xfree (psd);
4449 return NULL;
4452 return psd;
4455 static DWORD
4456 get_rid (PSID sid)
4458 unsigned n_subauthorities;
4460 /* Use the last sub-authority value of the RID, the relative
4461 portion of the SID, as user/group ID. */
4462 n_subauthorities = *get_sid_sub_authority_count (sid);
4463 if (n_subauthorities < 1)
4464 return 0; /* the "World" RID */
4465 return *get_sid_sub_authority (sid, n_subauthorities - 1);
4468 /* Caching SID and account values for faster lokup. */
4470 struct w32_id {
4471 unsigned rid;
4472 struct w32_id *next;
4473 char name[GNLEN+1];
4474 unsigned char sid[FLEXIBLE_ARRAY_MEMBER];
4477 static struct w32_id *w32_idlist;
4479 static int
4480 w32_cached_id (PSID sid, unsigned *id, char *name)
4482 struct w32_id *tail, *found;
4484 for (found = NULL, tail = w32_idlist; tail; tail = tail->next)
4486 if (equal_sid ((PSID)tail->sid, sid))
4488 found = tail;
4489 break;
4492 if (found)
4494 *id = found->rid;
4495 strcpy (name, found->name);
4496 return 1;
4498 else
4499 return 0;
4502 static void
4503 w32_add_to_cache (PSID sid, unsigned id, char *name)
4505 DWORD sid_len;
4506 struct w32_id *new_entry;
4508 /* We don't want to leave behind stale cache from when Emacs was
4509 dumped. */
4510 if (initialized)
4512 sid_len = get_length_sid (sid);
4513 new_entry = xmalloc (offsetof (struct w32_id, sid) + sid_len);
4514 if (new_entry)
4516 new_entry->rid = id;
4517 strcpy (new_entry->name, name);
4518 copy_sid (sid_len, (PSID)new_entry->sid, sid);
4519 new_entry->next = w32_idlist;
4520 w32_idlist = new_entry;
4525 #define UID 1
4526 #define GID 2
4528 static int
4529 get_name_and_id (PSECURITY_DESCRIPTOR psd, unsigned *id, char *nm, int what)
4531 PSID sid = NULL;
4532 BOOL dflt;
4533 SID_NAME_USE ignore;
4534 char name[UNLEN+1];
4535 DWORD name_len = sizeof (name);
4536 char domain[1024];
4537 DWORD domain_len = sizeof (domain);
4538 int use_dflt = 0;
4539 int result;
4541 if (what == UID)
4542 result = get_security_descriptor_owner (psd, &sid, &dflt);
4543 else if (what == GID)
4544 result = get_security_descriptor_group (psd, &sid, &dflt);
4545 else
4546 result = 0;
4548 if (!result || !is_valid_sid (sid))
4549 use_dflt = 1;
4550 else if (!w32_cached_id (sid, id, nm))
4552 if (!lookup_account_sid (NULL, sid, name, &name_len,
4553 domain, &domain_len, &ignore)
4554 || name_len > UNLEN+1)
4555 use_dflt = 1;
4556 else
4558 *id = get_rid (sid);
4559 strcpy (nm, name);
4560 w32_add_to_cache (sid, *id, name);
4563 return use_dflt;
4566 static void
4567 get_file_owner_and_group (PSECURITY_DESCRIPTOR psd, struct stat *st)
4569 int dflt_usr = 0, dflt_grp = 0;
4571 if (!psd)
4573 dflt_usr = 1;
4574 dflt_grp = 1;
4576 else
4578 if (get_name_and_id (psd, &st->st_uid, st->st_uname, UID))
4579 dflt_usr = 1;
4580 if (get_name_and_id (psd, &st->st_gid, st->st_gname, GID))
4581 dflt_grp = 1;
4583 /* Consider files to belong to current user/group, if we cannot get
4584 more accurate information. */
4585 if (dflt_usr)
4587 st->st_uid = dflt_passwd.pw_uid;
4588 strcpy (st->st_uname, dflt_passwd.pw_name);
4590 if (dflt_grp)
4592 st->st_gid = dflt_passwd.pw_gid;
4593 strcpy (st->st_gname, dflt_group.gr_name);
4597 /* Return non-zero if NAME is a potentially slow filesystem. */
4599 is_slow_fs (const char *name)
4601 char drive_root[4];
4602 UINT devtype;
4604 if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
4605 devtype = DRIVE_REMOTE; /* assume UNC name is remote */
4606 else if (!(strlen (name) >= 2 && IS_DEVICE_SEP (name[1])))
4607 devtype = GetDriveType (NULL); /* use root of current drive */
4608 else
4610 /* GetDriveType needs the root directory of the drive. */
4611 strncpy (drive_root, name, 2);
4612 drive_root[2] = '\\';
4613 drive_root[3] = '\0';
4614 devtype = GetDriveType (drive_root);
4616 return !(devtype == DRIVE_FIXED || devtype == DRIVE_RAMDISK);
4619 /* If this is non-zero, the caller wants accurate information about
4620 file's owner and group, which could be expensive to get. dired.c
4621 uses this flag when needed for the job at hand. */
4622 int w32_stat_get_owner_group;
4624 /* MSVC stat function can't cope with UNC names and has other bugs, so
4625 replace it with our own. This also allows us to calculate consistent
4626 inode values and owner/group without hacks in the main Emacs code,
4627 and support file names encoded in UTF-8. */
4629 static int
4630 stat_worker (const char * path, struct stat * buf, int follow_symlinks)
4632 char *name, *save_name, *r;
4633 WIN32_FIND_DATAW wfd_w;
4634 WIN32_FIND_DATAA wfd_a;
4635 HANDLE fh;
4636 unsigned __int64 fake_inode = 0;
4637 int permission;
4638 int len;
4639 int rootdir = FALSE;
4640 PSECURITY_DESCRIPTOR psd = NULL;
4641 int is_a_symlink = 0;
4642 DWORD file_flags = FILE_FLAG_BACKUP_SEMANTICS;
4643 DWORD access_rights = 0;
4644 DWORD fattrs = 0, serialnum = 0, fs_high = 0, fs_low = 0, nlinks = 1;
4645 FILETIME ctime, atime, wtime;
4646 wchar_t name_w[MAX_PATH];
4647 char name_a[MAX_PATH];
4649 if (path == NULL || buf == NULL)
4651 errno = EFAULT;
4652 return -1;
4655 save_name = name = (char *) map_w32_filename (path, &path);
4656 /* Must be valid filename, no wild cards or other invalid
4657 characters. */
4658 if (strpbrk (name, "*?|<>\""))
4660 errno = ENOENT;
4661 return -1;
4664 /* Remove trailing directory separator, unless name is the root
4665 directory of a drive or UNC volume in which case ensure there
4666 is a trailing separator. */
4667 len = strlen (name);
4668 name = strcpy (alloca (len + 2), name);
4670 /* Avoid a somewhat costly call to is_symlink if the filesystem
4671 doesn't support symlinks. */
4672 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
4673 is_a_symlink = is_symlink (name);
4675 /* Plan A: Open the file and get all the necessary information via
4676 the resulting handle. This solves several issues in one blow:
4678 . retrieves attributes for the target of a symlink, if needed
4679 . gets attributes of root directories and symlinks pointing to
4680 root directories, thus avoiding the need for special-casing
4681 these and detecting them by examining the file-name format
4682 . retrieves more accurate attributes (e.g., non-zero size for
4683 some directories, esp. directories that are junction points)
4684 . correctly resolves "c:/..", "/.." and similar file names
4685 . avoids run-time penalties for 99% of use cases
4687 Plan A is always tried first, unless the user asked not to (but
4688 if the file is a symlink and we need to follow links, we try Plan
4689 A even if the user asked not to).
4691 If Plan A fails, we go to Plan B (below), where various
4692 potentially expensive techniques must be used to handle "special"
4693 files such as UNC volumes etc. */
4694 if (!(NILP (Vw32_get_true_file_attributes)
4695 || (EQ (Vw32_get_true_file_attributes, Qlocal) && is_slow_fs (name)))
4696 /* Following symlinks requires getting the info by handle. */
4697 || (is_a_symlink && follow_symlinks))
4699 BY_HANDLE_FILE_INFORMATION info;
4701 if (is_a_symlink && !follow_symlinks)
4702 file_flags |= FILE_FLAG_OPEN_REPARSE_POINT;
4703 /* READ_CONTROL access rights are required to get security info
4704 by handle. But if the OS doesn't support security in the
4705 first place, we don't need to try. */
4706 if (is_windows_9x () != TRUE)
4707 access_rights |= READ_CONTROL;
4709 if (w32_unicode_filenames)
4711 filename_to_utf16 (name, name_w);
4712 fh = CreateFileW (name_w, access_rights, 0, NULL, OPEN_EXISTING,
4713 file_flags, NULL);
4714 /* If CreateFile fails with READ_CONTROL, try again with
4715 zero as access rights. */
4716 if (fh == INVALID_HANDLE_VALUE && access_rights)
4717 fh = CreateFileW (name_w, 0, 0, NULL, OPEN_EXISTING,
4718 file_flags, NULL);
4720 else
4722 filename_to_ansi (name, name_a);
4723 fh = CreateFileA (name_a, access_rights, 0, NULL, OPEN_EXISTING,
4724 file_flags, NULL);
4725 if (fh == INVALID_HANDLE_VALUE && access_rights)
4726 fh = CreateFileA (name_a, 0, 0, NULL, OPEN_EXISTING,
4727 file_flags, NULL);
4729 if (fh == INVALID_HANDLE_VALUE)
4730 goto no_true_file_attributes;
4732 /* This is more accurate in terms of getting the correct number
4733 of links, but is quite slow (it is noticeable when Emacs is
4734 making a list of file name completions). */
4735 if (GetFileInformationByHandle (fh, &info))
4737 nlinks = info.nNumberOfLinks;
4738 /* Might as well use file index to fake inode values, but this
4739 is not guaranteed to be unique unless we keep a handle open
4740 all the time (even then there are situations where it is
4741 not unique). Reputedly, there are at most 48 bits of info
4742 (on NTFS, presumably less on FAT). */
4743 fake_inode = info.nFileIndexHigh;
4744 fake_inode <<= 32;
4745 fake_inode += info.nFileIndexLow;
4746 serialnum = info.dwVolumeSerialNumber;
4747 fs_high = info.nFileSizeHigh;
4748 fs_low = info.nFileSizeLow;
4749 ctime = info.ftCreationTime;
4750 atime = info.ftLastAccessTime;
4751 wtime = info.ftLastWriteTime;
4752 fattrs = info.dwFileAttributes;
4754 else
4756 /* We don't go to Plan B here, because it's not clear that
4757 it's a good idea. The only known use case where
4758 CreateFile succeeds, but GetFileInformationByHandle fails
4759 (with ERROR_INVALID_FUNCTION) is for character devices
4760 such as NUL, PRN, etc. For these, switching to Plan B is
4761 a net loss, because we lose the character device
4762 attribute returned by GetFileType below (FindFirstFile
4763 doesn't set that bit in the attributes), and the other
4764 fields don't make sense for character devices anyway.
4765 Emacs doesn't really care for non-file entities in the
4766 context of l?stat, so neither do we. */
4768 /* w32err is assigned so one could put a breakpoint here and
4769 examine its value, when GetFileInformationByHandle
4770 fails. */
4771 DWORD w32err = GetLastError ();
4773 switch (w32err)
4775 case ERROR_FILE_NOT_FOUND: /* can this ever happen? */
4776 errno = ENOENT;
4777 return -1;
4781 /* Test for a symlink before testing for a directory, since
4782 symlinks to directories have the directory bit set, but we
4783 don't want them to appear as directories. */
4784 if (is_a_symlink && !follow_symlinks)
4785 buf->st_mode = S_IFLNK;
4786 else if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
4787 buf->st_mode = S_IFDIR;
4788 else
4790 DWORD ftype = GetFileType (fh);
4792 switch (ftype)
4794 case FILE_TYPE_DISK:
4795 buf->st_mode = S_IFREG;
4796 break;
4797 case FILE_TYPE_PIPE:
4798 buf->st_mode = S_IFIFO;
4799 break;
4800 case FILE_TYPE_CHAR:
4801 case FILE_TYPE_UNKNOWN:
4802 default:
4803 buf->st_mode = S_IFCHR;
4806 /* We produce the fallback owner and group data, based on the
4807 current user that runs Emacs, in the following cases:
4809 . caller didn't request owner and group info
4810 . this is Windows 9X
4811 . getting security by handle failed, and we need to produce
4812 information for the target of a symlink (this is better
4813 than producing a potentially misleading info about the
4814 symlink itself)
4816 If getting security by handle fails, and we don't need to
4817 resolve symlinks, we try getting security by name. */
4818 if (!w32_stat_get_owner_group || is_windows_9x () == TRUE)
4819 get_file_owner_and_group (NULL, buf);
4820 else
4822 psd = get_file_security_desc_by_handle (fh);
4823 if (psd)
4825 get_file_owner_and_group (psd, buf);
4826 LocalFree (psd);
4828 else if (!(is_a_symlink && follow_symlinks))
4830 psd = get_file_security_desc_by_name (name);
4831 get_file_owner_and_group (psd, buf);
4832 xfree (psd);
4834 else
4835 get_file_owner_and_group (NULL, buf);
4837 CloseHandle (fh);
4839 else
4841 no_true_file_attributes:
4842 /* Plan B: Either getting a handle on the file failed, or the
4843 caller explicitly asked us to not bother making this
4844 information more accurate.
4846 Implementation note: In Plan B, we never bother to resolve
4847 symlinks, even if we got here because we tried Plan A and
4848 failed. That's because, even if the caller asked for extra
4849 precision by setting Vw32_get_true_file_attributes to t,
4850 resolving symlinks requires acquiring a file handle to the
4851 symlink, which we already know will fail. And if the user
4852 did not ask for extra precision, resolving symlinks will fly
4853 in the face of that request, since the user then wants the
4854 lightweight version of the code. */
4855 rootdir = (path >= save_name + len - 1
4856 && (IS_DIRECTORY_SEP (*path) || *path == 0));
4858 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
4859 r = IS_DEVICE_SEP (name[1]) ? &name[2] : name;
4860 if (IS_DIRECTORY_SEP (r[0])
4861 && r[1] == '.' && r[2] == '.' && r[3] == '\0')
4862 r[1] = r[2] = '\0';
4864 /* Note: If NAME is a symlink to the root of a UNC volume
4865 (i.e. "\\SERVER"), we will not detect that here, and we will
4866 return data about the symlink as result of FindFirst below.
4867 This is unfortunate, but that marginal use case does not
4868 justify a call to chase_symlinks which would impose a penalty
4869 on all the other use cases. (We get here for symlinks to
4870 roots of UNC volumes because CreateFile above fails for them,
4871 unlike with symlinks to root directories X:\ of drives.) */
4872 if (is_unc_volume (name))
4874 fattrs = unc_volume_file_attributes (name);
4875 if (fattrs == -1)
4876 return -1;
4878 ctime = atime = wtime = utc_base_ft;
4880 else if (rootdir)
4882 if (!IS_DIRECTORY_SEP (name[len-1]))
4883 strcat (name, "\\");
4884 if (GetDriveType (name) < 2)
4886 errno = ENOENT;
4887 return -1;
4890 fattrs = FILE_ATTRIBUTE_DIRECTORY;
4891 ctime = atime = wtime = utc_base_ft;
4893 else
4895 int have_wfd = -1;
4897 if (IS_DIRECTORY_SEP (name[len-1]))
4898 name[len - 1] = 0;
4900 /* (This is hacky, but helps when doing file completions on
4901 network drives.) Optimize by using information available from
4902 active readdir if possible. */
4903 len = strlen (dir_pathname);
4904 if (IS_DIRECTORY_SEP (dir_pathname[len-1]))
4905 len--;
4906 if (dir_find_handle != INVALID_HANDLE_VALUE
4907 && last_dir_find_data != -1
4908 && !(is_a_symlink && follow_symlinks)
4909 /* The 2 file-name comparisons below support only ASCII
4910 characters, and will lose (compare not equal) when
4911 the file names include non-ASCII characters that are
4912 the same but for the case. However, doing this
4913 properly involves: (a) converting both file names to
4914 UTF-16, (b) lower-casing both names using CharLowerW,
4915 and (c) comparing the results; this would be quite a
4916 bit slower, whereas Plan B is for users who want
4917 lightweight albeit inaccurate version of 'stat'. */
4918 && c_strncasecmp (save_name, dir_pathname, len) == 0
4919 && IS_DIRECTORY_SEP (name[len])
4920 && xstrcasecmp (name + len + 1, dir_static.d_name) == 0)
4922 have_wfd = last_dir_find_data;
4923 /* This was the last entry returned by readdir. */
4924 if (last_dir_find_data == DIR_FIND_DATA_W)
4925 wfd_w = dir_find_data_w;
4926 else
4927 wfd_a = dir_find_data_a;
4929 else
4931 logon_network_drive (name);
4933 if (w32_unicode_filenames)
4935 filename_to_utf16 (name, name_w);
4936 fh = FindFirstFileW (name_w, &wfd_w);
4937 have_wfd = DIR_FIND_DATA_W;
4939 else
4941 filename_to_ansi (name, name_a);
4942 /* If NAME includes characters not representable by
4943 the current ANSI codepage, filename_to_ansi
4944 usually replaces them with a '?'. We don't want
4945 to let FindFirstFileA interpret those as wildcards,
4946 and "succeed", returning us data from some random
4947 file in the same directory. */
4948 if (_mbspbrk (name_a, "?"))
4949 fh = INVALID_HANDLE_VALUE;
4950 else
4951 fh = FindFirstFileA (name_a, &wfd_a);
4952 have_wfd = DIR_FIND_DATA_A;
4954 if (fh == INVALID_HANDLE_VALUE)
4956 errno = ENOENT;
4957 return -1;
4959 FindClose (fh);
4961 /* Note: if NAME is a symlink, the information we get from
4962 FindFirstFile is for the symlink, not its target. */
4963 if (have_wfd == DIR_FIND_DATA_W)
4965 fattrs = wfd_w.dwFileAttributes;
4966 ctime = wfd_w.ftCreationTime;
4967 atime = wfd_w.ftLastAccessTime;
4968 wtime = wfd_w.ftLastWriteTime;
4969 fs_high = wfd_w.nFileSizeHigh;
4970 fs_low = wfd_w.nFileSizeLow;
4972 else
4974 fattrs = wfd_a.dwFileAttributes;
4975 ctime = wfd_a.ftCreationTime;
4976 atime = wfd_a.ftLastAccessTime;
4977 wtime = wfd_a.ftLastWriteTime;
4978 fs_high = wfd_a.nFileSizeHigh;
4979 fs_low = wfd_a.nFileSizeLow;
4981 fake_inode = 0;
4982 nlinks = 1;
4983 serialnum = volume_info.serialnum;
4985 if (is_a_symlink && !follow_symlinks)
4986 buf->st_mode = S_IFLNK;
4987 else if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
4988 buf->st_mode = S_IFDIR;
4989 else
4990 buf->st_mode = S_IFREG;
4992 get_file_owner_and_group (NULL, buf);
4995 buf->st_ino = fake_inode;
4997 buf->st_dev = serialnum;
4998 buf->st_rdev = serialnum;
5000 buf->st_size = fs_high;
5001 buf->st_size <<= 32;
5002 buf->st_size += fs_low;
5003 buf->st_nlink = nlinks;
5005 /* Convert timestamps to Unix format. */
5006 buf->st_mtime = convert_time (wtime);
5007 buf->st_atime = convert_time (atime);
5008 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
5009 buf->st_ctime = convert_time (ctime);
5010 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
5012 /* determine rwx permissions */
5013 if (is_a_symlink && !follow_symlinks)
5014 permission = S_IREAD | S_IWRITE | S_IEXEC; /* Posix expectations */
5015 else
5017 if (fattrs & FILE_ATTRIBUTE_READONLY)
5018 permission = S_IREAD;
5019 else
5020 permission = S_IREAD | S_IWRITE;
5022 if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
5023 permission |= S_IEXEC;
5024 else if (is_exec (name))
5025 permission |= S_IEXEC;
5028 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
5030 return 0;
5034 stat (const char * path, struct stat * buf)
5036 return stat_worker (path, buf, 1);
5040 lstat (const char * path, struct stat * buf)
5042 return stat_worker (path, buf, 0);
5046 fstatat (int fd, char const *name, struct stat *st, int flags)
5048 /* Rely on a hack: an open directory is modeled as file descriptor 0.
5049 This is good enough for the current usage in Emacs, but is fragile.
5051 FIXME: Add proper support for fdopendir, fstatat, readlinkat.
5052 Gnulib does this and can serve as a model. */
5053 char fullname[MAX_UTF8_PATH];
5055 if (fd != AT_FDCWD)
5057 if (_snprintf (fullname, sizeof fullname, "%s/%s", dir_pathname, name)
5058 < 0)
5060 errno = ENAMETOOLONG;
5061 return -1;
5063 name = fullname;
5066 return stat_worker (name, st, ! (flags & AT_SYMLINK_NOFOLLOW));
5069 /* Provide fstat and utime as well as stat for consistent handling of
5070 file timestamps. */
5072 fstat (int desc, struct stat * buf)
5074 HANDLE fh = (HANDLE) _get_osfhandle (desc);
5075 BY_HANDLE_FILE_INFORMATION info;
5076 unsigned __int64 fake_inode;
5077 int permission;
5079 switch (GetFileType (fh) & ~FILE_TYPE_REMOTE)
5081 case FILE_TYPE_DISK:
5082 buf->st_mode = S_IFREG;
5083 if (!GetFileInformationByHandle (fh, &info))
5085 errno = EACCES;
5086 return -1;
5088 break;
5089 case FILE_TYPE_PIPE:
5090 buf->st_mode = S_IFIFO;
5091 goto non_disk;
5092 case FILE_TYPE_CHAR:
5093 case FILE_TYPE_UNKNOWN:
5094 default:
5095 buf->st_mode = S_IFCHR;
5096 non_disk:
5097 memset (&info, 0, sizeof (info));
5098 info.dwFileAttributes = 0;
5099 info.ftCreationTime = utc_base_ft;
5100 info.ftLastAccessTime = utc_base_ft;
5101 info.ftLastWriteTime = utc_base_ft;
5104 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
5105 buf->st_mode = S_IFDIR;
5107 buf->st_nlink = info.nNumberOfLinks;
5108 /* Might as well use file index to fake inode values, but this
5109 is not guaranteed to be unique unless we keep a handle open
5110 all the time (even then there are situations where it is
5111 not unique). Reputedly, there are at most 48 bits of info
5112 (on NTFS, presumably less on FAT). */
5113 fake_inode = info.nFileIndexHigh;
5114 fake_inode <<= 32;
5115 fake_inode += info.nFileIndexLow;
5117 /* MSVC defines _ino_t to be short; other libc's might not. */
5118 if (sizeof (buf->st_ino) == 2)
5119 buf->st_ino = fake_inode ^ (fake_inode >> 16);
5120 else
5121 buf->st_ino = fake_inode;
5123 /* If the caller so requested, get the true file owner and group.
5124 Otherwise, consider the file to belong to the current user. */
5125 if (!w32_stat_get_owner_group || is_windows_9x () == TRUE)
5126 get_file_owner_and_group (NULL, buf);
5127 else
5129 PSECURITY_DESCRIPTOR psd = NULL;
5131 psd = get_file_security_desc_by_handle (fh);
5132 if (psd)
5134 get_file_owner_and_group (psd, buf);
5135 LocalFree (psd);
5137 else
5138 get_file_owner_and_group (NULL, buf);
5141 buf->st_dev = info.dwVolumeSerialNumber;
5142 buf->st_rdev = info.dwVolumeSerialNumber;
5144 buf->st_size = info.nFileSizeHigh;
5145 buf->st_size <<= 32;
5146 buf->st_size += info.nFileSizeLow;
5148 /* Convert timestamps to Unix format. */
5149 buf->st_mtime = convert_time (info.ftLastWriteTime);
5150 buf->st_atime = convert_time (info.ftLastAccessTime);
5151 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
5152 buf->st_ctime = convert_time (info.ftCreationTime);
5153 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
5155 /* determine rwx permissions */
5156 if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
5157 permission = S_IREAD;
5158 else
5159 permission = S_IREAD | S_IWRITE;
5161 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
5162 permission |= S_IEXEC;
5163 else
5165 #if 0 /* no way of knowing the filename */
5166 char * p = strrchr (name, '.');
5167 if (p != NULL &&
5168 (xstrcasecmp (p, ".exe") == 0 ||
5169 xstrcasecmp (p, ".com") == 0 ||
5170 xstrcasecmp (p, ".bat") == 0 ||
5171 xstrcasecmp (p, ".cmd") == 0))
5172 permission |= S_IEXEC;
5173 #endif
5176 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
5178 return 0;
5181 /* A version of 'utime' which handles directories as well as
5182 files. */
5185 utime (const char *name, struct utimbuf *times)
5187 struct utimbuf deftime;
5188 HANDLE fh;
5189 FILETIME mtime;
5190 FILETIME atime;
5192 if (times == NULL)
5194 deftime.modtime = deftime.actime = time (NULL);
5195 times = &deftime;
5198 if (w32_unicode_filenames)
5200 wchar_t name_utf16[MAX_PATH];
5202 if (filename_to_utf16 (name, name_utf16) != 0)
5203 return -1; /* errno set by filename_to_utf16 */
5205 /* Need write access to set times. */
5206 fh = CreateFileW (name_utf16, FILE_WRITE_ATTRIBUTES,
5207 /* If NAME specifies a directory, FILE_SHARE_DELETE
5208 allows other processes to delete files inside it,
5209 while we have the directory open. */
5210 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
5211 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
5213 else
5215 char name_ansi[MAX_PATH];
5217 if (filename_to_ansi (name, name_ansi) != 0)
5218 return -1; /* errno set by filename_to_ansi */
5220 fh = CreateFileA (name_ansi, FILE_WRITE_ATTRIBUTES,
5221 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
5222 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
5224 if (fh != INVALID_HANDLE_VALUE)
5226 convert_from_time_t (times->actime, &atime);
5227 convert_from_time_t (times->modtime, &mtime);
5228 if (!SetFileTime (fh, NULL, &atime, &mtime))
5230 CloseHandle (fh);
5231 errno = EACCES;
5232 return -1;
5234 CloseHandle (fh);
5236 else
5238 DWORD err = GetLastError ();
5240 switch (err)
5242 case ERROR_FILE_NOT_FOUND:
5243 case ERROR_PATH_NOT_FOUND:
5244 case ERROR_INVALID_DRIVE:
5245 case ERROR_BAD_NETPATH:
5246 case ERROR_DEV_NOT_EXIST:
5247 /* ERROR_INVALID_NAME is the error CreateFile sets when the
5248 file name includes ?s, i.e. translation to ANSI failed. */
5249 case ERROR_INVALID_NAME:
5250 errno = ENOENT;
5251 break;
5252 case ERROR_TOO_MANY_OPEN_FILES:
5253 errno = ENFILE;
5254 break;
5255 case ERROR_ACCESS_DENIED:
5256 case ERROR_SHARING_VIOLATION:
5257 errno = EACCES;
5258 break;
5259 default:
5260 errno = EINVAL;
5261 break;
5263 return -1;
5265 return 0;
5269 /* Symlink-related functions. */
5270 #ifndef SYMBOLIC_LINK_FLAG_DIRECTORY
5271 #define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1
5272 #endif
5275 symlink (char const *filename, char const *linkname)
5277 char linkfn[MAX_UTF8_PATH], *tgtfn;
5278 DWORD flags = 0;
5279 int dir_access, filename_ends_in_slash;
5281 /* Diagnostics follows Posix as much as possible. */
5282 if (filename == NULL || linkname == NULL)
5284 errno = EFAULT;
5285 return -1;
5287 if (!*filename)
5289 errno = ENOENT;
5290 return -1;
5292 if (strlen (filename) > MAX_UTF8_PATH || strlen (linkname) > MAX_UTF8_PATH)
5294 errno = ENAMETOOLONG;
5295 return -1;
5298 strcpy (linkfn, map_w32_filename (linkname, NULL));
5299 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) == 0)
5301 errno = EPERM;
5302 return -1;
5305 /* Note: since empty FILENAME was already rejected, we can safely
5306 refer to FILENAME[1]. */
5307 if (!(IS_DIRECTORY_SEP (filename[0]) || IS_DEVICE_SEP (filename[1])))
5309 /* Non-absolute FILENAME is understood as being relative to
5310 LINKNAME's directory. We need to prepend that directory to
5311 FILENAME to get correct results from faccessat below, since
5312 otherwise it will interpret FILENAME relative to the
5313 directory where the Emacs process runs. Note that
5314 make-symbolic-link always makes sure LINKNAME is a fully
5315 expanded file name. */
5316 char tem[MAX_UTF8_PATH];
5317 char *p = linkfn + strlen (linkfn);
5319 while (p > linkfn && !IS_ANY_SEP (p[-1]))
5320 p--;
5321 if (p > linkfn)
5322 strncpy (tem, linkfn, p - linkfn);
5323 tem[p - linkfn] = '\0';
5324 strcat (tem, filename);
5325 dir_access = faccessat (AT_FDCWD, tem, D_OK, AT_EACCESS);
5327 else
5328 dir_access = faccessat (AT_FDCWD, filename, D_OK, AT_EACCESS);
5330 /* Since Windows distinguishes between symlinks to directories and
5331 to files, we provide a kludgy feature: if FILENAME doesn't
5332 exist, but ends in a slash, we create a symlink to directory. If
5333 FILENAME exists and is a directory, we always create a symlink to
5334 directory. */
5335 filename_ends_in_slash = IS_DIRECTORY_SEP (filename[strlen (filename) - 1]);
5336 if (dir_access == 0 || filename_ends_in_slash)
5337 flags = SYMBOLIC_LINK_FLAG_DIRECTORY;
5339 tgtfn = (char *)map_w32_filename (filename, NULL);
5340 if (filename_ends_in_slash)
5341 tgtfn[strlen (tgtfn) - 1] = '\0';
5343 errno = 0;
5344 if (!create_symbolic_link (linkfn, tgtfn, flags))
5346 /* ENOSYS is set by create_symbolic_link, when it detects that
5347 the OS doesn't support the CreateSymbolicLink API. */
5348 if (errno != ENOSYS)
5350 DWORD w32err = GetLastError ();
5352 switch (w32err)
5354 /* ERROR_SUCCESS is sometimes returned when LINKFN and
5355 TGTFN point to the same file name, go figure. */
5356 case ERROR_SUCCESS:
5357 case ERROR_FILE_EXISTS:
5358 errno = EEXIST;
5359 break;
5360 case ERROR_ACCESS_DENIED:
5361 errno = EACCES;
5362 break;
5363 case ERROR_FILE_NOT_FOUND:
5364 case ERROR_PATH_NOT_FOUND:
5365 case ERROR_BAD_NETPATH:
5366 case ERROR_INVALID_REPARSE_DATA:
5367 errno = ENOENT;
5368 break;
5369 case ERROR_DIRECTORY:
5370 errno = EISDIR;
5371 break;
5372 case ERROR_PRIVILEGE_NOT_HELD:
5373 case ERROR_NOT_ALL_ASSIGNED:
5374 errno = EPERM;
5375 break;
5376 case ERROR_DISK_FULL:
5377 errno = ENOSPC;
5378 break;
5379 default:
5380 errno = EINVAL;
5381 break;
5384 return -1;
5386 return 0;
5389 /* A quick inexpensive test of whether FILENAME identifies a file that
5390 is a symlink. Returns non-zero if it is, zero otherwise. FILENAME
5391 must already be in the normalized form returned by
5392 map_w32_filename.
5394 Note: for repeated operations on many files, it is best to test
5395 whether the underlying volume actually supports symlinks, by
5396 testing the FILE_SUPPORTS_REPARSE_POINTS bit in volume's flags, and
5397 avoid the call to this function if it doesn't. That's because the
5398 call to GetFileAttributes takes a non-negligible time, especially
5399 on non-local or removable filesystems. See stat_worker for an
5400 example of how to do that. */
5401 static int
5402 is_symlink (const char *filename)
5404 DWORD attrs;
5405 wchar_t filename_w[MAX_PATH];
5406 char filename_a[MAX_PATH];
5407 WIN32_FIND_DATAW wfdw;
5408 WIN32_FIND_DATAA wfda;
5409 HANDLE fh;
5410 int attrs_mean_symlink;
5412 if (w32_unicode_filenames)
5414 filename_to_utf16 (filename, filename_w);
5415 attrs = GetFileAttributesW (filename_w);
5417 else
5419 filename_to_ansi (filename, filename_a);
5420 attrs = GetFileAttributesA (filename_a);
5422 if (attrs == -1)
5424 DWORD w32err = GetLastError ();
5426 switch (w32err)
5428 case ERROR_BAD_NETPATH: /* network share, can't be a symlink */
5429 break;
5430 case ERROR_ACCESS_DENIED:
5431 errno = EACCES;
5432 break;
5433 case ERROR_FILE_NOT_FOUND:
5434 case ERROR_PATH_NOT_FOUND:
5435 default:
5436 errno = ENOENT;
5437 break;
5439 return 0;
5441 if ((attrs & FILE_ATTRIBUTE_REPARSE_POINT) == 0)
5442 return 0;
5443 logon_network_drive (filename);
5444 if (w32_unicode_filenames)
5446 fh = FindFirstFileW (filename_w, &wfdw);
5447 attrs_mean_symlink =
5448 (wfdw.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0
5449 && (wfdw.dwReserved0 & IO_REPARSE_TAG_SYMLINK) == IO_REPARSE_TAG_SYMLINK;
5451 else if (_mbspbrk (filename_a, "?"))
5453 /* filename_to_ansi failed to convert the file name. */
5454 errno = ENOENT;
5455 return 0;
5457 else
5459 fh = FindFirstFileA (filename_a, &wfda);
5460 attrs_mean_symlink =
5461 (wfda.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0
5462 && (wfda.dwReserved0 & IO_REPARSE_TAG_SYMLINK) == IO_REPARSE_TAG_SYMLINK;
5464 if (fh == INVALID_HANDLE_VALUE)
5465 return 0;
5466 FindClose (fh);
5467 return attrs_mean_symlink;
5470 /* If NAME identifies a symbolic link, copy into BUF the file name of
5471 the symlink's target. Copy at most BUF_SIZE bytes, and do NOT
5472 null-terminate the target name, even if it fits. Return the number
5473 of bytes copied, or -1 if NAME is not a symlink or any error was
5474 encountered while resolving it. The file name copied into BUF is
5475 encoded in the current ANSI codepage. */
5476 ssize_t
5477 readlink (const char *name, char *buf, size_t buf_size)
5479 const char *path;
5480 TOKEN_PRIVILEGES privs;
5481 int restore_privs = 0;
5482 HANDLE sh;
5483 ssize_t retval;
5484 char resolved[MAX_UTF8_PATH];
5486 if (name == NULL)
5488 errno = EFAULT;
5489 return -1;
5491 if (!*name)
5493 errno = ENOENT;
5494 return -1;
5497 path = map_w32_filename (name, NULL);
5499 if (strlen (path) > MAX_UTF8_PATH)
5501 errno = ENAMETOOLONG;
5502 return -1;
5505 errno = 0;
5506 if (is_windows_9x () == TRUE
5507 || (volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) == 0
5508 || !is_symlink (path))
5510 if (!errno)
5511 errno = EINVAL; /* not a symlink */
5512 return -1;
5515 /* Done with simple tests, now we're in for some _real_ work. */
5516 if (enable_privilege (SE_BACKUP_NAME, TRUE, &privs))
5517 restore_privs = 1;
5518 /* Implementation note: From here and onward, don't return early,
5519 since that will fail to restore the original set of privileges of
5520 the calling thread. */
5522 retval = -1; /* not too optimistic, are we? */
5524 /* Note: In the next call to CreateFile, we use zero as the 2nd
5525 argument because, when the symlink is a hidden/system file,
5526 e.g. 'C:\Users\All Users', GENERIC_READ fails with
5527 ERROR_ACCESS_DENIED. Zero seems to work just fine, both for file
5528 and directory symlinks. */
5529 if (w32_unicode_filenames)
5531 wchar_t path_w[MAX_PATH];
5533 filename_to_utf16 (path, path_w);
5534 sh = CreateFileW (path_w, 0, 0, NULL, OPEN_EXISTING,
5535 FILE_FLAG_OPEN_REPARSE_POINT
5536 | FILE_FLAG_BACKUP_SEMANTICS,
5537 NULL);
5539 else
5541 char path_a[MAX_PATH];
5543 filename_to_ansi (path, path_a);
5544 sh = CreateFileA (path_a, 0, 0, NULL, OPEN_EXISTING,
5545 FILE_FLAG_OPEN_REPARSE_POINT
5546 | FILE_FLAG_BACKUP_SEMANTICS,
5547 NULL);
5549 if (sh != INVALID_HANDLE_VALUE)
5551 BYTE reparse_buf[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
5552 REPARSE_DATA_BUFFER *reparse_data = (REPARSE_DATA_BUFFER *)&reparse_buf[0];
5553 DWORD retbytes;
5555 if (!DeviceIoControl (sh, FSCTL_GET_REPARSE_POINT, NULL, 0,
5556 reparse_buf, MAXIMUM_REPARSE_DATA_BUFFER_SIZE,
5557 &retbytes, NULL))
5558 errno = EIO;
5559 else if (reparse_data->ReparseTag != IO_REPARSE_TAG_SYMLINK)
5560 errno = EINVAL;
5561 else
5563 /* Copy the link target name, in wide characters, from
5564 reparse_data, then convert it to multibyte encoding in
5565 the current locale's codepage. */
5566 WCHAR *lwname;
5567 size_t lname_size;
5568 USHORT lwname_len =
5569 reparse_data->SymbolicLinkReparseBuffer.PrintNameLength;
5570 WCHAR *lwname_src =
5571 reparse_data->SymbolicLinkReparseBuffer.PathBuffer
5572 + reparse_data->SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(WCHAR);
5573 size_t size_to_copy = buf_size;
5575 /* According to MSDN, PrintNameLength does not include the
5576 terminating null character. */
5577 lwname = alloca ((lwname_len + 1) * sizeof(WCHAR));
5578 memcpy (lwname, lwname_src, lwname_len);
5579 lwname[lwname_len/sizeof(WCHAR)] = 0; /* null-terminate */
5580 filename_from_utf16 (lwname, resolved);
5581 dostounix_filename (resolved);
5582 lname_size = strlen (resolved) + 1;
5583 if (lname_size <= buf_size)
5584 size_to_copy = lname_size;
5585 strncpy (buf, resolved, size_to_copy);
5586 /* Success! */
5587 retval = size_to_copy;
5589 CloseHandle (sh);
5591 else
5593 /* CreateFile failed. */
5594 DWORD w32err2 = GetLastError ();
5596 switch (w32err2)
5598 case ERROR_FILE_NOT_FOUND:
5599 case ERROR_PATH_NOT_FOUND:
5600 errno = ENOENT;
5601 break;
5602 case ERROR_ACCESS_DENIED:
5603 case ERROR_TOO_MANY_OPEN_FILES:
5604 errno = EACCES;
5605 break;
5606 default:
5607 errno = EPERM;
5608 break;
5611 if (restore_privs)
5613 restore_privilege (&privs);
5614 revert_to_self ();
5617 return retval;
5620 ssize_t
5621 readlinkat (int fd, char const *name, char *buffer,
5622 size_t buffer_size)
5624 /* Rely on a hack: an open directory is modeled as file descriptor 0,
5625 as in fstatat. FIXME: Add proper support for readlinkat. */
5626 char fullname[MAX_UTF8_PATH];
5628 if (fd != AT_FDCWD)
5630 if (_snprintf (fullname, sizeof fullname, "%s/%s", dir_pathname, name)
5631 < 0)
5633 errno = ENAMETOOLONG;
5634 return -1;
5636 name = fullname;
5639 return readlink (name, buffer, buffer_size);
5642 /* If FILE is a symlink, return its target (stored in a static
5643 buffer); otherwise return FILE.
5645 This function repeatedly resolves symlinks in the last component of
5646 a chain of symlink file names, as in foo -> bar -> baz -> ...,
5647 until it arrives at a file whose last component is not a symlink,
5648 or some error occurs. It returns the target of the last
5649 successfully resolved symlink in the chain. If it succeeds to
5650 resolve even a single symlink, the value returned is an absolute
5651 file name with backslashes (result of GetFullPathName). By
5652 contrast, if the original FILE is returned, it is unaltered.
5654 Note: This function can set errno even if it succeeds.
5656 Implementation note: we only resolve the last portion ("basename")
5657 of the argument FILE and of each following file in the chain,
5658 disregarding any possible symlinks in its leading directories.
5659 This is because Windows system calls and library functions
5660 transparently resolve symlinks in leading directories and return
5661 correct information, as long as the basename is not a symlink. */
5662 static char *
5663 chase_symlinks (const char *file)
5665 static char target[MAX_UTF8_PATH];
5666 char link[MAX_UTF8_PATH];
5667 wchar_t target_w[MAX_PATH], link_w[MAX_PATH];
5668 char target_a[MAX_PATH], link_a[MAX_PATH];
5669 ssize_t res, link_len;
5670 int loop_count = 0;
5672 if (is_windows_9x () == TRUE || !is_symlink (file))
5673 return (char *)file;
5675 if (w32_unicode_filenames)
5677 wchar_t file_w[MAX_PATH];
5679 filename_to_utf16 (file, file_w);
5680 if (GetFullPathNameW (file_w, MAX_PATH, link_w, NULL) == 0)
5681 return (char *)file;
5682 filename_from_utf16 (link_w, link);
5684 else
5686 char file_a[MAX_PATH];
5688 filename_to_ansi (file, file_a);
5689 if (GetFullPathNameA (file_a, MAX_PATH, link_a, NULL) == 0)
5690 return (char *)file;
5691 filename_from_ansi (link_a, link);
5693 link_len = strlen (link);
5695 target[0] = '\0';
5696 do {
5698 /* Remove trailing slashes, as we want to resolve the last
5699 non-trivial part of the link name. */
5700 while (link_len > 3 && IS_DIRECTORY_SEP (link[link_len-1]))
5701 link[link_len--] = '\0';
5703 res = readlink (link, target, MAX_UTF8_PATH);
5704 if (res > 0)
5706 target[res] = '\0';
5707 if (!(IS_DEVICE_SEP (target[1])
5708 || (IS_DIRECTORY_SEP (target[0]) && IS_DIRECTORY_SEP (target[1]))))
5710 /* Target is relative. Append it to the directory part of
5711 the symlink, then copy the result back to target. */
5712 char *p = link + link_len;
5714 while (p > link && !IS_ANY_SEP (p[-1]))
5715 p--;
5716 strcpy (p, target);
5717 strcpy (target, link);
5719 /* Resolve any "." and ".." to get a fully-qualified file name
5720 in link[] again. */
5721 if (w32_unicode_filenames)
5723 filename_to_utf16 (target, target_w);
5724 link_len = GetFullPathNameW (target_w, MAX_PATH, link_w, NULL);
5725 if (link_len > 0)
5726 filename_from_utf16 (link_w, link);
5728 else
5730 filename_to_ansi (target, target_a);
5731 link_len = GetFullPathNameA (target_a, MAX_PATH, link_a, NULL);
5732 if (link_len > 0)
5733 filename_from_ansi (link_a, link);
5735 link_len = strlen (link);
5737 } while (res > 0 && link_len > 0 && ++loop_count <= 100);
5739 if (loop_count > 100)
5740 errno = ELOOP;
5742 if (target[0] == '\0') /* not a single call to readlink succeeded */
5743 return (char *)file;
5744 return target;
5748 /* Posix ACL emulation. */
5751 acl_valid (acl_t acl)
5753 return is_valid_security_descriptor ((PSECURITY_DESCRIPTOR)acl) ? 0 : -1;
5756 char *
5757 acl_to_text (acl_t acl, ssize_t *size)
5759 LPTSTR str_acl;
5760 SECURITY_INFORMATION flags =
5761 OWNER_SECURITY_INFORMATION |
5762 GROUP_SECURITY_INFORMATION |
5763 DACL_SECURITY_INFORMATION;
5764 char *retval = NULL;
5765 ULONG local_size;
5766 int e = errno;
5768 errno = 0;
5770 if (convert_sd_to_sddl ((PSECURITY_DESCRIPTOR)acl, SDDL_REVISION_1, flags, &str_acl, &local_size))
5772 errno = e;
5773 /* We don't want to mix heaps, so we duplicate the string in our
5774 heap and free the one allocated by the API. */
5775 retval = xstrdup (str_acl);
5776 if (size)
5777 *size = local_size;
5778 LocalFree (str_acl);
5780 else if (errno != ENOTSUP)
5781 errno = EINVAL;
5783 return retval;
5786 acl_t
5787 acl_from_text (const char *acl_str)
5789 PSECURITY_DESCRIPTOR psd, retval = NULL;
5790 ULONG sd_size;
5791 int e = errno;
5793 errno = 0;
5795 if (convert_sddl_to_sd (acl_str, SDDL_REVISION_1, &psd, &sd_size))
5797 errno = e;
5798 retval = xmalloc (sd_size);
5799 memcpy (retval, psd, sd_size);
5800 LocalFree (psd);
5802 else if (errno != ENOTSUP)
5803 errno = EINVAL;
5805 return retval;
5809 acl_free (void *ptr)
5811 xfree (ptr);
5812 return 0;
5815 acl_t
5816 acl_get_file (const char *fname, acl_type_t type)
5818 PSECURITY_DESCRIPTOR psd = NULL;
5819 const char *filename;
5821 if (type == ACL_TYPE_ACCESS)
5823 DWORD sd_len, err;
5824 SECURITY_INFORMATION si =
5825 OWNER_SECURITY_INFORMATION |
5826 GROUP_SECURITY_INFORMATION |
5827 DACL_SECURITY_INFORMATION ;
5828 int e = errno;
5830 filename = map_w32_filename (fname, NULL);
5831 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
5832 fname = chase_symlinks (filename);
5833 else
5834 fname = filename;
5836 errno = 0;
5837 if (!get_file_security (fname, si, psd, 0, &sd_len)
5838 && errno != ENOTSUP)
5840 err = GetLastError ();
5841 if (err == ERROR_INSUFFICIENT_BUFFER)
5843 psd = xmalloc (sd_len);
5844 if (!get_file_security (fname, si, psd, sd_len, &sd_len))
5846 xfree (psd);
5847 errno = EIO;
5848 psd = NULL;
5851 else if (err == ERROR_FILE_NOT_FOUND
5852 || err == ERROR_PATH_NOT_FOUND
5853 /* ERROR_INVALID_NAME is what we get if
5854 w32-unicode-filenames is nil and the file cannot
5855 be encoded in the current ANSI codepage. */
5856 || err == ERROR_INVALID_NAME)
5857 errno = ENOENT;
5858 else
5859 errno = EIO;
5861 else if (!errno)
5862 errno = e;
5864 else if (type != ACL_TYPE_DEFAULT)
5865 errno = EINVAL;
5867 return psd;
5871 acl_set_file (const char *fname, acl_type_t type, acl_t acl)
5873 TOKEN_PRIVILEGES old1, old2;
5874 DWORD err;
5875 int st = 0, retval = -1;
5876 SECURITY_INFORMATION flags = 0;
5877 PSID psid;
5878 PACL pacl;
5879 BOOL dflt;
5880 BOOL dacl_present;
5881 int e;
5882 const char *filename;
5884 if (acl_valid (acl) != 0
5885 || (type != ACL_TYPE_DEFAULT && type != ACL_TYPE_ACCESS))
5887 errno = EINVAL;
5888 return -1;
5891 if (type == ACL_TYPE_DEFAULT)
5893 errno = ENOSYS;
5894 return -1;
5897 filename = map_w32_filename (fname, NULL);
5898 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
5899 fname = chase_symlinks (filename);
5900 else
5901 fname = filename;
5903 if (get_security_descriptor_owner ((PSECURITY_DESCRIPTOR)acl, &psid, &dflt)
5904 && psid)
5905 flags |= OWNER_SECURITY_INFORMATION;
5906 if (get_security_descriptor_group ((PSECURITY_DESCRIPTOR)acl, &psid, &dflt)
5907 && psid)
5908 flags |= GROUP_SECURITY_INFORMATION;
5909 if (get_security_descriptor_dacl ((PSECURITY_DESCRIPTOR)acl, &dacl_present,
5910 &pacl, &dflt)
5911 && dacl_present)
5912 flags |= DACL_SECURITY_INFORMATION;
5913 if (!flags)
5914 return 0;
5916 /* According to KB-245153, setting the owner will succeed if either:
5917 (1) the caller is the user who will be the new owner, and has the
5918 SE_TAKE_OWNERSHIP privilege, or
5919 (2) the caller has the SE_RESTORE privilege, in which case she can
5920 set any valid user or group as the owner
5922 We request below both SE_TAKE_OWNERSHIP and SE_RESTORE
5923 privileges, and disregard any failures in obtaining them. If
5924 these privileges cannot be obtained, and do not already exist in
5925 the calling thread's security token, this function could fail
5926 with EPERM. */
5927 if (enable_privilege (SE_TAKE_OWNERSHIP_NAME, TRUE, &old1))
5928 st++;
5929 if (enable_privilege (SE_RESTORE_NAME, TRUE, &old2))
5930 st++;
5932 e = errno;
5933 errno = 0;
5934 if (!set_file_security (fname, flags, (PSECURITY_DESCRIPTOR)acl))
5936 err = GetLastError ();
5938 if (errno == ENOTSUP)
5940 else if (err == ERROR_INVALID_OWNER
5941 || err == ERROR_NOT_ALL_ASSIGNED
5942 || err == ERROR_ACCESS_DENIED)
5944 /* Maybe the requested ACL and the one the file already has
5945 are identical, in which case we can silently ignore the
5946 failure. (And no, Windows doesn't.) */
5947 acl_t current_acl = acl_get_file (fname, ACL_TYPE_ACCESS);
5949 errno = EPERM;
5950 if (current_acl)
5952 char *acl_from = acl_to_text (current_acl, NULL);
5953 char *acl_to = acl_to_text (acl, NULL);
5955 if (acl_from && acl_to && xstrcasecmp (acl_from, acl_to) == 0)
5957 retval = 0;
5958 errno = e;
5960 if (acl_from)
5961 acl_free (acl_from);
5962 if (acl_to)
5963 acl_free (acl_to);
5964 acl_free (current_acl);
5967 else if (err == ERROR_FILE_NOT_FOUND
5968 || err == ERROR_PATH_NOT_FOUND
5969 /* ERROR_INVALID_NAME is what we get if
5970 w32-unicode-filenames is nil and the file cannot be
5971 encoded in the current ANSI codepage. */
5972 || err == ERROR_INVALID_NAME)
5973 errno = ENOENT;
5974 else
5975 errno = EACCES;
5977 else
5979 retval = 0;
5980 errno = e;
5983 if (st)
5985 if (st >= 2)
5986 restore_privilege (&old2);
5987 restore_privilege (&old1);
5988 revert_to_self ();
5991 return retval;
5995 /* MS-Windows version of careadlinkat (cf. ../lib/careadlinkat.c). We
5996 have a fixed max size for file names, so we don't need the kind of
5997 alloc/malloc/realloc dance the gnulib version does. We also don't
5998 support FD-relative symlinks. */
5999 char *
6000 careadlinkat (int fd, char const *filename,
6001 char *buffer, size_t buffer_size,
6002 struct allocator const *alloc,
6003 ssize_t (*preadlinkat) (int, char const *, char *, size_t))
6005 char linkname[MAX_UTF8_PATH];
6006 ssize_t link_size;
6008 link_size = preadlinkat (fd, filename, linkname, sizeof(linkname));
6010 if (link_size > 0)
6012 char *retval = buffer;
6014 linkname[link_size++] = '\0';
6015 if (link_size > buffer_size)
6016 retval = (char *)(alloc ? alloc->allocate : xmalloc) (link_size);
6017 if (retval)
6018 memcpy (retval, linkname, link_size);
6020 return retval;
6022 return NULL;
6026 w32_copy_file (const char *from, const char *to,
6027 int keep_time, int preserve_ownership, int copy_acls)
6029 acl_t acl = NULL;
6030 BOOL copy_result;
6031 wchar_t from_w[MAX_PATH], to_w[MAX_PATH];
6032 char from_a[MAX_PATH], to_a[MAX_PATH];
6034 /* We ignore preserve_ownership for now. */
6035 preserve_ownership = preserve_ownership;
6037 if (copy_acls)
6039 acl = acl_get_file (from, ACL_TYPE_ACCESS);
6040 if (acl == NULL && acl_errno_valid (errno))
6041 return -2;
6043 if (w32_unicode_filenames)
6045 filename_to_utf16 (from, from_w);
6046 filename_to_utf16 (to, to_w);
6047 copy_result = CopyFileW (from_w, to_w, FALSE);
6049 else
6051 filename_to_ansi (from, from_a);
6052 filename_to_ansi (to, to_a);
6053 copy_result = CopyFileA (from_a, to_a, FALSE);
6055 if (!copy_result)
6057 /* CopyFile doesn't set errno when it fails. By far the most
6058 "popular" reason is that the target is read-only. */
6059 DWORD err = GetLastError ();
6061 switch (err)
6063 case ERROR_FILE_NOT_FOUND:
6064 errno = ENOENT;
6065 break;
6066 case ERROR_ACCESS_DENIED:
6067 errno = EACCES;
6068 break;
6069 case ERROR_ENCRYPTION_FAILED:
6070 errno = EIO;
6071 break;
6072 default:
6073 errno = EPERM;
6074 break;
6077 if (acl)
6078 acl_free (acl);
6079 return -1;
6081 /* CopyFile retains the timestamp by default. However, see
6082 "Community Additions" for CopyFile: it sounds like that is not
6083 entirely true. Testing on Windows XP confirms that modified time
6084 is copied, but creation and last-access times are not.
6085 FIXME? */
6086 else if (!keep_time)
6088 struct timespec now;
6089 DWORD attributes;
6091 if (w32_unicode_filenames)
6093 /* Ensure file is writable while its times are set. */
6094 attributes = GetFileAttributesW (to_w);
6095 SetFileAttributesW (to_w, attributes & ~FILE_ATTRIBUTE_READONLY);
6096 now = current_timespec ();
6097 if (set_file_times (-1, to, now, now))
6099 /* Restore original attributes. */
6100 SetFileAttributesW (to_w, attributes);
6101 if (acl)
6102 acl_free (acl);
6103 return -3;
6105 /* Restore original attributes. */
6106 SetFileAttributesW (to_w, attributes);
6108 else
6110 attributes = GetFileAttributesA (to_a);
6111 SetFileAttributesA (to_a, attributes & ~FILE_ATTRIBUTE_READONLY);
6112 now = current_timespec ();
6113 if (set_file_times (-1, to, now, now))
6115 SetFileAttributesA (to_a, attributes);
6116 if (acl)
6117 acl_free (acl);
6118 return -3;
6120 SetFileAttributesA (to_a, attributes);
6123 if (acl != NULL)
6125 bool fail =
6126 acl_set_file (to, ACL_TYPE_ACCESS, acl) != 0;
6127 acl_free (acl);
6128 if (fail && acl_errno_valid (errno))
6129 return -4;
6132 return 0;
6136 /* Support for browsing other processes and their attributes. See
6137 process.c for the Lisp bindings. */
6139 /* Helper wrapper functions. */
6141 static HANDLE WINAPI
6142 create_toolhelp32_snapshot (DWORD Flags, DWORD Ignored)
6144 static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot = NULL;
6146 if (g_b_init_create_toolhelp32_snapshot == 0)
6148 g_b_init_create_toolhelp32_snapshot = 1;
6149 s_pfn_Create_Toolhelp32_Snapshot = (CreateToolhelp32Snapshot_Proc)
6150 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6151 "CreateToolhelp32Snapshot");
6153 if (s_pfn_Create_Toolhelp32_Snapshot == NULL)
6155 return INVALID_HANDLE_VALUE;
6157 return (s_pfn_Create_Toolhelp32_Snapshot (Flags, Ignored));
6160 static BOOL WINAPI
6161 process32_first (HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
6163 static Process32First_Proc s_pfn_Process32_First = NULL;
6165 if (g_b_init_process32_first == 0)
6167 g_b_init_process32_first = 1;
6168 s_pfn_Process32_First = (Process32First_Proc)
6169 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6170 "Process32First");
6172 if (s_pfn_Process32_First == NULL)
6174 return FALSE;
6176 return (s_pfn_Process32_First (hSnapshot, lppe));
6179 static BOOL WINAPI
6180 process32_next (HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
6182 static Process32Next_Proc s_pfn_Process32_Next = NULL;
6184 if (g_b_init_process32_next == 0)
6186 g_b_init_process32_next = 1;
6187 s_pfn_Process32_Next = (Process32Next_Proc)
6188 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6189 "Process32Next");
6191 if (s_pfn_Process32_Next == NULL)
6193 return FALSE;
6195 return (s_pfn_Process32_Next (hSnapshot, lppe));
6198 static BOOL WINAPI
6199 open_thread_token (HANDLE ThreadHandle,
6200 DWORD DesiredAccess,
6201 BOOL OpenAsSelf,
6202 PHANDLE TokenHandle)
6204 static OpenThreadToken_Proc s_pfn_Open_Thread_Token = NULL;
6205 HMODULE hm_advapi32 = NULL;
6206 if (is_windows_9x () == TRUE)
6208 SetLastError (ERROR_NOT_SUPPORTED);
6209 return FALSE;
6211 if (g_b_init_open_thread_token == 0)
6213 g_b_init_open_thread_token = 1;
6214 hm_advapi32 = LoadLibrary ("Advapi32.dll");
6215 s_pfn_Open_Thread_Token =
6216 (OpenThreadToken_Proc) GetProcAddress (hm_advapi32, "OpenThreadToken");
6218 if (s_pfn_Open_Thread_Token == NULL)
6220 SetLastError (ERROR_NOT_SUPPORTED);
6221 return FALSE;
6223 return (
6224 s_pfn_Open_Thread_Token (
6225 ThreadHandle,
6226 DesiredAccess,
6227 OpenAsSelf,
6228 TokenHandle)
6232 static BOOL WINAPI
6233 impersonate_self (SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
6235 static ImpersonateSelf_Proc s_pfn_Impersonate_Self = NULL;
6236 HMODULE hm_advapi32 = NULL;
6237 if (is_windows_9x () == TRUE)
6239 return FALSE;
6241 if (g_b_init_impersonate_self == 0)
6243 g_b_init_impersonate_self = 1;
6244 hm_advapi32 = LoadLibrary ("Advapi32.dll");
6245 s_pfn_Impersonate_Self =
6246 (ImpersonateSelf_Proc) GetProcAddress (hm_advapi32, "ImpersonateSelf");
6248 if (s_pfn_Impersonate_Self == NULL)
6250 return FALSE;
6252 return s_pfn_Impersonate_Self (ImpersonationLevel);
6255 static BOOL WINAPI
6256 revert_to_self (void)
6258 static RevertToSelf_Proc s_pfn_Revert_To_Self = NULL;
6259 HMODULE hm_advapi32 = NULL;
6260 if (is_windows_9x () == TRUE)
6262 return FALSE;
6264 if (g_b_init_revert_to_self == 0)
6266 g_b_init_revert_to_self = 1;
6267 hm_advapi32 = LoadLibrary ("Advapi32.dll");
6268 s_pfn_Revert_To_Self =
6269 (RevertToSelf_Proc) GetProcAddress (hm_advapi32, "RevertToSelf");
6271 if (s_pfn_Revert_To_Self == NULL)
6273 return FALSE;
6275 return s_pfn_Revert_To_Self ();
6278 static BOOL WINAPI
6279 get_process_memory_info (HANDLE h_proc,
6280 PPROCESS_MEMORY_COUNTERS mem_counters,
6281 DWORD bufsize)
6283 static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info = NULL;
6284 HMODULE hm_psapi = NULL;
6285 if (is_windows_9x () == TRUE)
6287 return FALSE;
6289 if (g_b_init_get_process_memory_info == 0)
6291 g_b_init_get_process_memory_info = 1;
6292 hm_psapi = LoadLibrary ("Psapi.dll");
6293 if (hm_psapi)
6294 s_pfn_Get_Process_Memory_Info = (GetProcessMemoryInfo_Proc)
6295 GetProcAddress (hm_psapi, "GetProcessMemoryInfo");
6297 if (s_pfn_Get_Process_Memory_Info == NULL)
6299 return FALSE;
6301 return s_pfn_Get_Process_Memory_Info (h_proc, mem_counters, bufsize);
6304 static BOOL WINAPI
6305 get_process_working_set_size (HANDLE h_proc,
6306 PSIZE_T minrss,
6307 PSIZE_T maxrss)
6309 static GetProcessWorkingSetSize_Proc
6310 s_pfn_Get_Process_Working_Set_Size = NULL;
6312 if (is_windows_9x () == TRUE)
6314 return FALSE;
6316 if (g_b_init_get_process_working_set_size == 0)
6318 g_b_init_get_process_working_set_size = 1;
6319 s_pfn_Get_Process_Working_Set_Size = (GetProcessWorkingSetSize_Proc)
6320 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6321 "GetProcessWorkingSetSize");
6323 if (s_pfn_Get_Process_Working_Set_Size == NULL)
6325 return FALSE;
6327 return s_pfn_Get_Process_Working_Set_Size (h_proc, minrss, maxrss);
6330 static BOOL WINAPI
6331 global_memory_status (MEMORYSTATUS *buf)
6333 static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status = NULL;
6335 if (is_windows_9x () == TRUE)
6337 return FALSE;
6339 if (g_b_init_global_memory_status == 0)
6341 g_b_init_global_memory_status = 1;
6342 s_pfn_Global_Memory_Status = (GlobalMemoryStatus_Proc)
6343 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6344 "GlobalMemoryStatus");
6346 if (s_pfn_Global_Memory_Status == NULL)
6348 return FALSE;
6350 return s_pfn_Global_Memory_Status (buf);
6353 static BOOL WINAPI
6354 global_memory_status_ex (MEMORY_STATUS_EX *buf)
6356 static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex = NULL;
6358 if (is_windows_9x () == TRUE)
6360 return FALSE;
6362 if (g_b_init_global_memory_status_ex == 0)
6364 g_b_init_global_memory_status_ex = 1;
6365 s_pfn_Global_Memory_Status_Ex = (GlobalMemoryStatusEx_Proc)
6366 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6367 "GlobalMemoryStatusEx");
6369 if (s_pfn_Global_Memory_Status_Ex == NULL)
6371 return FALSE;
6373 return s_pfn_Global_Memory_Status_Ex (buf);
6376 Lisp_Object
6377 list_system_processes (void)
6379 struct gcpro gcpro1;
6380 Lisp_Object proclist = Qnil;
6381 HANDLE h_snapshot;
6383 h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
6385 if (h_snapshot != INVALID_HANDLE_VALUE)
6387 PROCESSENTRY32 proc_entry;
6388 DWORD proc_id;
6389 BOOL res;
6391 GCPRO1 (proclist);
6393 proc_entry.dwSize = sizeof (PROCESSENTRY32);
6394 for (res = process32_first (h_snapshot, &proc_entry); res;
6395 res = process32_next (h_snapshot, &proc_entry))
6397 proc_id = proc_entry.th32ProcessID;
6398 proclist = Fcons (make_fixnum_or_float (proc_id), proclist);
6401 CloseHandle (h_snapshot);
6402 UNGCPRO;
6403 proclist = Fnreverse (proclist);
6406 return proclist;
6409 static int
6410 enable_privilege (LPCTSTR priv_name, BOOL enable_p, TOKEN_PRIVILEGES *old_priv)
6412 TOKEN_PRIVILEGES priv;
6413 DWORD priv_size = sizeof (priv);
6414 DWORD opriv_size = sizeof (*old_priv);
6415 HANDLE h_token = NULL;
6416 HANDLE h_thread = GetCurrentThread ();
6417 int ret_val = 0;
6418 BOOL res;
6420 res = open_thread_token (h_thread,
6421 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
6422 FALSE, &h_token);
6423 if (!res && GetLastError () == ERROR_NO_TOKEN)
6425 if (impersonate_self (SecurityImpersonation))
6426 res = open_thread_token (h_thread,
6427 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
6428 FALSE, &h_token);
6430 if (res)
6432 priv.PrivilegeCount = 1;
6433 priv.Privileges[0].Attributes = enable_p ? SE_PRIVILEGE_ENABLED : 0;
6434 LookupPrivilegeValue (NULL, priv_name, &priv.Privileges[0].Luid);
6435 if (AdjustTokenPrivileges (h_token, FALSE, &priv, priv_size,
6436 old_priv, &opriv_size)
6437 && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
6438 ret_val = 1;
6440 if (h_token)
6441 CloseHandle (h_token);
6443 return ret_val;
6446 static int
6447 restore_privilege (TOKEN_PRIVILEGES *priv)
6449 DWORD priv_size = sizeof (*priv);
6450 HANDLE h_token = NULL;
6451 int ret_val = 0;
6453 if (open_thread_token (GetCurrentThread (),
6454 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
6455 FALSE, &h_token))
6457 if (AdjustTokenPrivileges (h_token, FALSE, priv, priv_size, NULL, NULL)
6458 && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
6459 ret_val = 1;
6461 if (h_token)
6462 CloseHandle (h_token);
6464 return ret_val;
6467 static Lisp_Object
6468 ltime (ULONGLONG time_100ns)
6470 ULONGLONG time_sec = time_100ns / 10000000;
6471 int subsec = time_100ns % 10000000;
6472 return list4i (time_sec >> 16, time_sec & 0xffff,
6473 subsec / 10, subsec % 10 * 100000);
6476 #define U64_TO_LISP_TIME(time) ltime (time)
6478 static int
6479 process_times (HANDLE h_proc, Lisp_Object *ctime, Lisp_Object *etime,
6480 Lisp_Object *stime, Lisp_Object *utime, Lisp_Object *ttime,
6481 double *pcpu)
6483 FILETIME ft_creation, ft_exit, ft_kernel, ft_user, ft_current;
6484 ULONGLONG tem1, tem2, tem3, tem;
6486 if (!h_proc
6487 || !get_process_times_fn
6488 || !(*get_process_times_fn) (h_proc, &ft_creation, &ft_exit,
6489 &ft_kernel, &ft_user))
6490 return 0;
6492 GetSystemTimeAsFileTime (&ft_current);
6494 FILETIME_TO_U64 (tem1, ft_kernel);
6495 *stime = U64_TO_LISP_TIME (tem1);
6497 FILETIME_TO_U64 (tem2, ft_user);
6498 *utime = U64_TO_LISP_TIME (tem2);
6500 tem3 = tem1 + tem2;
6501 *ttime = U64_TO_LISP_TIME (tem3);
6503 FILETIME_TO_U64 (tem, ft_creation);
6504 /* Process no 4 (System) returns zero creation time. */
6505 if (tem)
6506 tem -= utc_base;
6507 *ctime = U64_TO_LISP_TIME (tem);
6509 if (tem)
6511 FILETIME_TO_U64 (tem3, ft_current);
6512 tem = (tem3 - utc_base) - tem;
6514 *etime = U64_TO_LISP_TIME (tem);
6516 if (tem)
6518 *pcpu = 100.0 * (tem1 + tem2) / tem;
6519 if (*pcpu > 100)
6520 *pcpu = 100.0;
6522 else
6523 *pcpu = 0;
6525 return 1;
6528 Lisp_Object
6529 system_process_attributes (Lisp_Object pid)
6531 struct gcpro gcpro1, gcpro2, gcpro3;
6532 Lisp_Object attrs = Qnil;
6533 Lisp_Object cmd_str, decoded_cmd, tem;
6534 HANDLE h_snapshot, h_proc;
6535 DWORD proc_id;
6536 int found_proc = 0;
6537 char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
6538 DWORD ulength = sizeof (uname), dlength = sizeof (domain), needed;
6539 DWORD glength = sizeof (gname);
6540 HANDLE token = NULL;
6541 SID_NAME_USE user_type;
6542 unsigned char *buf = NULL;
6543 DWORD blen = 0;
6544 TOKEN_USER user_token;
6545 TOKEN_PRIMARY_GROUP group_token;
6546 unsigned euid;
6547 unsigned egid;
6548 PROCESS_MEMORY_COUNTERS mem;
6549 PROCESS_MEMORY_COUNTERS_EX mem_ex;
6550 SIZE_T minrss, maxrss;
6551 MEMORYSTATUS memst;
6552 MEMORY_STATUS_EX memstex;
6553 double totphys = 0.0;
6554 Lisp_Object ctime, stime, utime, etime, ttime;
6555 double pcpu;
6556 BOOL result = FALSE;
6558 CHECK_NUMBER_OR_FLOAT (pid);
6559 proc_id = FLOATP (pid) ? XFLOAT_DATA (pid) : XINT (pid);
6561 h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
6563 GCPRO3 (attrs, decoded_cmd, tem);
6565 if (h_snapshot != INVALID_HANDLE_VALUE)
6567 PROCESSENTRY32 pe;
6568 BOOL res;
6570 pe.dwSize = sizeof (PROCESSENTRY32);
6571 for (res = process32_first (h_snapshot, &pe); res;
6572 res = process32_next (h_snapshot, &pe))
6574 if (proc_id == pe.th32ProcessID)
6576 if (proc_id == 0)
6577 decoded_cmd = build_string ("Idle");
6578 else
6580 /* Decode the command name from locale-specific
6581 encoding. */
6582 cmd_str = build_unibyte_string (pe.szExeFile);
6584 decoded_cmd =
6585 code_convert_string_norecord (cmd_str,
6586 Vlocale_coding_system, 0);
6588 attrs = Fcons (Fcons (Qcomm, decoded_cmd), attrs);
6589 attrs = Fcons (Fcons (Qppid,
6590 make_fixnum_or_float (pe.th32ParentProcessID)),
6591 attrs);
6592 attrs = Fcons (Fcons (Qpri, make_number (pe.pcPriClassBase)),
6593 attrs);
6594 attrs = Fcons (Fcons (Qthcount,
6595 make_fixnum_or_float (pe.cntThreads)),
6596 attrs);
6597 found_proc = 1;
6598 break;
6602 CloseHandle (h_snapshot);
6605 if (!found_proc)
6607 UNGCPRO;
6608 return Qnil;
6611 h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
6612 FALSE, proc_id);
6613 /* If we were denied a handle to the process, try again after
6614 enabling the SeDebugPrivilege in our process. */
6615 if (!h_proc)
6617 TOKEN_PRIVILEGES priv_current;
6619 if (enable_privilege (SE_DEBUG_NAME, TRUE, &priv_current))
6621 h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
6622 FALSE, proc_id);
6623 restore_privilege (&priv_current);
6624 revert_to_self ();
6627 if (h_proc)
6629 result = open_process_token (h_proc, TOKEN_QUERY, &token);
6630 if (result)
6632 result = get_token_information (token, TokenUser, NULL, 0, &blen);
6633 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
6635 buf = xmalloc (blen);
6636 result = get_token_information (token, TokenUser,
6637 (LPVOID)buf, blen, &needed);
6638 if (result)
6640 memcpy (&user_token, buf, sizeof (user_token));
6641 if (!w32_cached_id (user_token.User.Sid, &euid, uname))
6643 euid = get_rid (user_token.User.Sid);
6644 result = lookup_account_sid (NULL, user_token.User.Sid,
6645 uname, &ulength,
6646 domain, &dlength,
6647 &user_type);
6648 if (result)
6649 w32_add_to_cache (user_token.User.Sid, euid, uname);
6650 else
6652 strcpy (uname, "unknown");
6653 result = TRUE;
6656 ulength = strlen (uname);
6660 if (result)
6662 /* Determine a reasonable euid and gid values. */
6663 if (xstrcasecmp ("administrator", uname) == 0)
6665 euid = 500; /* well-known Administrator uid */
6666 egid = 513; /* well-known None gid */
6668 else
6670 /* Get group id and name. */
6671 result = get_token_information (token, TokenPrimaryGroup,
6672 (LPVOID)buf, blen, &needed);
6673 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
6675 buf = xrealloc (buf, blen = needed);
6676 result = get_token_information (token, TokenPrimaryGroup,
6677 (LPVOID)buf, blen, &needed);
6679 if (result)
6681 memcpy (&group_token, buf, sizeof (group_token));
6682 if (!w32_cached_id (group_token.PrimaryGroup, &egid, gname))
6684 egid = get_rid (group_token.PrimaryGroup);
6685 dlength = sizeof (domain);
6686 result =
6687 lookup_account_sid (NULL, group_token.PrimaryGroup,
6688 gname, &glength, NULL, &dlength,
6689 &user_type);
6690 if (result)
6691 w32_add_to_cache (group_token.PrimaryGroup,
6692 egid, gname);
6693 else
6695 strcpy (gname, "None");
6696 result = TRUE;
6699 glength = strlen (gname);
6703 xfree (buf);
6705 if (!result)
6707 if (!is_windows_9x ())
6709 /* We couldn't open the process token, presumably because of
6710 insufficient access rights. Assume this process is run
6711 by the system. */
6712 strcpy (uname, "SYSTEM");
6713 strcpy (gname, "None");
6714 euid = 18; /* SYSTEM */
6715 egid = 513; /* None */
6716 glength = strlen (gname);
6717 ulength = strlen (uname);
6719 /* If we are running under Windows 9X, where security calls are
6720 not supported, we assume all processes are run by the current
6721 user. */
6722 else if (GetUserName (uname, &ulength))
6724 if (xstrcasecmp ("administrator", uname) == 0)
6725 euid = 0;
6726 else
6727 euid = 123;
6728 egid = euid;
6729 strcpy (gname, "None");
6730 glength = strlen (gname);
6731 ulength = strlen (uname);
6733 else
6735 euid = 123;
6736 egid = 123;
6737 strcpy (uname, "administrator");
6738 ulength = strlen (uname);
6739 strcpy (gname, "None");
6740 glength = strlen (gname);
6742 if (token)
6743 CloseHandle (token);
6746 attrs = Fcons (Fcons (Qeuid, make_fixnum_or_float (euid)), attrs);
6747 tem = make_unibyte_string (uname, ulength);
6748 attrs = Fcons (Fcons (Quser,
6749 code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
6750 attrs);
6751 attrs = Fcons (Fcons (Qegid, make_fixnum_or_float (egid)), attrs);
6752 tem = make_unibyte_string (gname, glength);
6753 attrs = Fcons (Fcons (Qgroup,
6754 code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
6755 attrs);
6757 if (global_memory_status_ex (&memstex))
6758 #if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
6759 totphys = memstex.ullTotalPhys / 1024.0;
6760 #else
6761 /* Visual Studio 6 cannot convert an unsigned __int64 type to
6762 double, so we need to do this for it... */
6764 DWORD tot_hi = memstex.ullTotalPhys >> 32;
6765 DWORD tot_md = (memstex.ullTotalPhys & 0x00000000ffffffff) >> 10;
6766 DWORD tot_lo = memstex.ullTotalPhys % 1024;
6768 totphys = tot_hi * 4194304.0 + tot_md + tot_lo / 1024.0;
6770 #endif /* __GNUC__ || _MSC_VER >= 1300 */
6771 else if (global_memory_status (&memst))
6772 totphys = memst.dwTotalPhys / 1024.0;
6774 if (h_proc
6775 && get_process_memory_info (h_proc, (PROCESS_MEMORY_COUNTERS *)&mem_ex,
6776 sizeof (mem_ex)))
6778 SIZE_T rss = mem_ex.WorkingSetSize / 1024;
6780 attrs = Fcons (Fcons (Qmajflt,
6781 make_fixnum_or_float (mem_ex.PageFaultCount)),
6782 attrs);
6783 attrs = Fcons (Fcons (Qvsize,
6784 make_fixnum_or_float (mem_ex.PrivateUsage / 1024)),
6785 attrs);
6786 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (rss)), attrs);
6787 if (totphys)
6788 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
6790 else if (h_proc
6791 && get_process_memory_info (h_proc, &mem, sizeof (mem)))
6793 SIZE_T rss = mem_ex.WorkingSetSize / 1024;
6795 attrs = Fcons (Fcons (Qmajflt,
6796 make_fixnum_or_float (mem.PageFaultCount)),
6797 attrs);
6798 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (rss)), attrs);
6799 if (totphys)
6800 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
6802 else if (h_proc
6803 && get_process_working_set_size (h_proc, &minrss, &maxrss))
6805 DWORD rss = maxrss / 1024;
6807 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (maxrss / 1024)), attrs);
6808 if (totphys)
6809 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
6812 if (process_times (h_proc, &ctime, &etime, &stime, &utime, &ttime, &pcpu))
6814 attrs = Fcons (Fcons (Qutime, utime), attrs);
6815 attrs = Fcons (Fcons (Qstime, stime), attrs);
6816 attrs = Fcons (Fcons (Qtime, ttime), attrs);
6817 attrs = Fcons (Fcons (Qstart, ctime), attrs);
6818 attrs = Fcons (Fcons (Qetime, etime), attrs);
6819 attrs = Fcons (Fcons (Qpcpu, make_float (pcpu)), attrs);
6822 /* FIXME: Retrieve command line by walking the PEB of the process. */
6824 if (h_proc)
6825 CloseHandle (h_proc);
6826 UNGCPRO;
6827 return attrs;
6831 /* Wrappers for winsock functions to map between our file descriptors
6832 and winsock's handles; also set h_errno for convenience.
6834 To allow Emacs to run on systems which don't have winsock support
6835 installed, we dynamically link to winsock on startup if present, and
6836 otherwise provide the minimum necessary functionality
6837 (eg. gethostname). */
6839 /* function pointers for relevant socket functions */
6840 int (PASCAL *pfn_WSAStartup) (WORD wVersionRequired, LPWSADATA lpWSAData);
6841 void (PASCAL *pfn_WSASetLastError) (int iError);
6842 int (PASCAL *pfn_WSAGetLastError) (void);
6843 int (PASCAL *pfn_WSAEventSelect) (SOCKET s, HANDLE hEventObject, long lNetworkEvents);
6844 HANDLE (PASCAL *pfn_WSACreateEvent) (void);
6845 int (PASCAL *pfn_WSACloseEvent) (HANDLE hEvent);
6846 int (PASCAL *pfn_socket) (int af, int type, int protocol);
6847 int (PASCAL *pfn_bind) (SOCKET s, const struct sockaddr *addr, int namelen);
6848 int (PASCAL *pfn_connect) (SOCKET s, const struct sockaddr *addr, int namelen);
6849 int (PASCAL *pfn_ioctlsocket) (SOCKET s, long cmd, u_long *argp);
6850 int (PASCAL *pfn_recv) (SOCKET s, char * buf, int len, int flags);
6851 int (PASCAL *pfn_send) (SOCKET s, const char * buf, int len, int flags);
6852 int (PASCAL *pfn_closesocket) (SOCKET s);
6853 int (PASCAL *pfn_shutdown) (SOCKET s, int how);
6854 int (PASCAL *pfn_WSACleanup) (void);
6856 u_short (PASCAL *pfn_htons) (u_short hostshort);
6857 u_short (PASCAL *pfn_ntohs) (u_short netshort);
6858 unsigned long (PASCAL *pfn_inet_addr) (const char * cp);
6859 int (PASCAL *pfn_gethostname) (char * name, int namelen);
6860 struct hostent * (PASCAL *pfn_gethostbyname) (const char * name);
6861 struct servent * (PASCAL *pfn_getservbyname) (const char * name, const char * proto);
6862 int (PASCAL *pfn_getpeername) (SOCKET s, struct sockaddr *addr, int * namelen);
6863 int (PASCAL *pfn_setsockopt) (SOCKET s, int level, int optname,
6864 const char * optval, int optlen);
6865 int (PASCAL *pfn_listen) (SOCKET s, int backlog);
6866 int (PASCAL *pfn_getsockname) (SOCKET s, struct sockaddr * name,
6867 int * namelen);
6868 SOCKET (PASCAL *pfn_accept) (SOCKET s, struct sockaddr * addr, int * addrlen);
6869 int (PASCAL *pfn_recvfrom) (SOCKET s, char * buf, int len, int flags,
6870 struct sockaddr * from, int * fromlen);
6871 int (PASCAL *pfn_sendto) (SOCKET s, const char * buf, int len, int flags,
6872 const struct sockaddr * to, int tolen);
6874 /* SetHandleInformation is only needed to make sockets non-inheritable. */
6875 BOOL (WINAPI *pfn_SetHandleInformation) (HANDLE object, DWORD mask, DWORD flags);
6876 #ifndef HANDLE_FLAG_INHERIT
6877 #define HANDLE_FLAG_INHERIT 1
6878 #endif
6880 HANDLE winsock_lib;
6881 static int winsock_inuse;
6883 BOOL
6884 term_winsock (void)
6886 if (winsock_lib != NULL && winsock_inuse == 0)
6888 release_listen_threads ();
6889 /* Not sure what would cause WSAENETDOWN, or even if it can happen
6890 after WSAStartup returns successfully, but it seems reasonable
6891 to allow unloading winsock anyway in that case. */
6892 if (pfn_WSACleanup () == 0 ||
6893 pfn_WSAGetLastError () == WSAENETDOWN)
6895 if (FreeLibrary (winsock_lib))
6896 winsock_lib = NULL;
6897 return TRUE;
6900 return FALSE;
6903 BOOL
6904 init_winsock (int load_now)
6906 WSADATA winsockData;
6908 if (winsock_lib != NULL)
6909 return TRUE;
6911 pfn_SetHandleInformation
6912 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
6913 "SetHandleInformation");
6915 winsock_lib = LoadLibrary ("Ws2_32.dll");
6917 if (winsock_lib != NULL)
6919 /* dynamically link to socket functions */
6921 #define LOAD_PROC(fn) \
6922 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
6923 goto fail;
6925 LOAD_PROC (WSAStartup);
6926 LOAD_PROC (WSASetLastError);
6927 LOAD_PROC (WSAGetLastError);
6928 LOAD_PROC (WSAEventSelect);
6929 LOAD_PROC (WSACreateEvent);
6930 LOAD_PROC (WSACloseEvent);
6931 LOAD_PROC (socket);
6932 LOAD_PROC (bind);
6933 LOAD_PROC (connect);
6934 LOAD_PROC (ioctlsocket);
6935 LOAD_PROC (recv);
6936 LOAD_PROC (send);
6937 LOAD_PROC (closesocket);
6938 LOAD_PROC (shutdown);
6939 LOAD_PROC (htons);
6940 LOAD_PROC (ntohs);
6941 LOAD_PROC (inet_addr);
6942 LOAD_PROC (gethostname);
6943 LOAD_PROC (gethostbyname);
6944 LOAD_PROC (getservbyname);
6945 LOAD_PROC (getpeername);
6946 LOAD_PROC (WSACleanup);
6947 LOAD_PROC (setsockopt);
6948 LOAD_PROC (listen);
6949 LOAD_PROC (getsockname);
6950 LOAD_PROC (accept);
6951 LOAD_PROC (recvfrom);
6952 LOAD_PROC (sendto);
6953 #undef LOAD_PROC
6955 /* specify version 1.1 of winsock */
6956 if (pfn_WSAStartup (0x101, &winsockData) == 0)
6958 if (winsockData.wVersion != 0x101)
6959 goto fail;
6961 if (!load_now)
6963 /* Report that winsock exists and is usable, but leave
6964 socket functions disabled. I am assuming that calling
6965 WSAStartup does not require any network interaction,
6966 and in particular does not cause or require a dial-up
6967 connection to be established. */
6969 pfn_WSACleanup ();
6970 FreeLibrary (winsock_lib);
6971 winsock_lib = NULL;
6973 winsock_inuse = 0;
6974 return TRUE;
6977 fail:
6978 FreeLibrary (winsock_lib);
6979 winsock_lib = NULL;
6982 return FALSE;
6986 int h_errno = 0;
6988 /* Function to map winsock error codes to errno codes for those errno
6989 code defined in errno.h (errno values not defined by errno.h are
6990 already in nt/inc/sys/socket.h). */
6991 static void
6992 set_errno (void)
6994 int wsa_err;
6996 h_errno = 0;
6997 if (winsock_lib == NULL)
6998 wsa_err = EINVAL;
6999 else
7000 wsa_err = pfn_WSAGetLastError ();
7002 switch (wsa_err)
7004 case WSAEACCES: errno = EACCES; break;
7005 case WSAEBADF: errno = EBADF; break;
7006 case WSAEFAULT: errno = EFAULT; break;
7007 case WSAEINTR: errno = EINTR; break;
7008 case WSAEINVAL: errno = EINVAL; break;
7009 case WSAEMFILE: errno = EMFILE; break;
7010 case WSAENAMETOOLONG: errno = ENAMETOOLONG; break;
7011 case WSAENOTEMPTY: errno = ENOTEMPTY; break;
7012 default: errno = wsa_err; break;
7016 static void
7017 check_errno (void)
7019 h_errno = 0;
7020 if (winsock_lib != NULL)
7021 pfn_WSASetLastError (0);
7024 /* Extend strerror to handle the winsock-specific error codes. */
7025 struct {
7026 int errnum;
7027 char * msg;
7028 } _wsa_errlist[] = {
7029 {WSAEINTR , "Interrupted function call"},
7030 {WSAEBADF , "Bad file descriptor"},
7031 {WSAEACCES , "Permission denied"},
7032 {WSAEFAULT , "Bad address"},
7033 {WSAEINVAL , "Invalid argument"},
7034 {WSAEMFILE , "Too many open files"},
7036 {WSAEWOULDBLOCK , "Resource temporarily unavailable"},
7037 {WSAEINPROGRESS , "Operation now in progress"},
7038 {WSAEALREADY , "Operation already in progress"},
7039 {WSAENOTSOCK , "Socket operation on non-socket"},
7040 {WSAEDESTADDRREQ , "Destination address required"},
7041 {WSAEMSGSIZE , "Message too long"},
7042 {WSAEPROTOTYPE , "Protocol wrong type for socket"},
7043 {WSAENOPROTOOPT , "Bad protocol option"},
7044 {WSAEPROTONOSUPPORT , "Protocol not supported"},
7045 {WSAESOCKTNOSUPPORT , "Socket type not supported"},
7046 {WSAEOPNOTSUPP , "Operation not supported"},
7047 {WSAEPFNOSUPPORT , "Protocol family not supported"},
7048 {WSAEAFNOSUPPORT , "Address family not supported by protocol family"},
7049 {WSAEADDRINUSE , "Address already in use"},
7050 {WSAEADDRNOTAVAIL , "Cannot assign requested address"},
7051 {WSAENETDOWN , "Network is down"},
7052 {WSAENETUNREACH , "Network is unreachable"},
7053 {WSAENETRESET , "Network dropped connection on reset"},
7054 {WSAECONNABORTED , "Software caused connection abort"},
7055 {WSAECONNRESET , "Connection reset by peer"},
7056 {WSAENOBUFS , "No buffer space available"},
7057 {WSAEISCONN , "Socket is already connected"},
7058 {WSAENOTCONN , "Socket is not connected"},
7059 {WSAESHUTDOWN , "Cannot send after socket shutdown"},
7060 {WSAETOOMANYREFS , "Too many references"}, /* not sure */
7061 {WSAETIMEDOUT , "Connection timed out"},
7062 {WSAECONNREFUSED , "Connection refused"},
7063 {WSAELOOP , "Network loop"}, /* not sure */
7064 {WSAENAMETOOLONG , "Name is too long"},
7065 {WSAEHOSTDOWN , "Host is down"},
7066 {WSAEHOSTUNREACH , "No route to host"},
7067 {WSAENOTEMPTY , "Buffer not empty"}, /* not sure */
7068 {WSAEPROCLIM , "Too many processes"},
7069 {WSAEUSERS , "Too many users"}, /* not sure */
7070 {WSAEDQUOT , "Double quote in host name"}, /* really not sure */
7071 {WSAESTALE , "Data is stale"}, /* not sure */
7072 {WSAEREMOTE , "Remote error"}, /* not sure */
7074 {WSASYSNOTREADY , "Network subsystem is unavailable"},
7075 {WSAVERNOTSUPPORTED , "WINSOCK.DLL version out of range"},
7076 {WSANOTINITIALISED , "Winsock not initialized successfully"},
7077 {WSAEDISCON , "Graceful shutdown in progress"},
7078 #ifdef WSAENOMORE
7079 {WSAENOMORE , "No more operations allowed"}, /* not sure */
7080 {WSAECANCELLED , "Operation cancelled"}, /* not sure */
7081 {WSAEINVALIDPROCTABLE , "Invalid procedure table from service provider"},
7082 {WSAEINVALIDPROVIDER , "Invalid service provider version number"},
7083 {WSAEPROVIDERFAILEDINIT , "Unable to initialize a service provider"},
7084 {WSASYSCALLFAILURE , "System call failure"},
7085 {WSASERVICE_NOT_FOUND , "Service not found"}, /* not sure */
7086 {WSATYPE_NOT_FOUND , "Class type not found"},
7087 {WSA_E_NO_MORE , "No more resources available"}, /* really not sure */
7088 {WSA_E_CANCELLED , "Operation already cancelled"}, /* really not sure */
7089 {WSAEREFUSED , "Operation refused"}, /* not sure */
7090 #endif
7092 {WSAHOST_NOT_FOUND , "Host not found"},
7093 {WSATRY_AGAIN , "Authoritative host not found during name lookup"},
7094 {WSANO_RECOVERY , "Non-recoverable error during name lookup"},
7095 {WSANO_DATA , "Valid name, no data record of requested type"},
7097 {-1, NULL}
7100 char *
7101 sys_strerror (int error_no)
7103 int i;
7104 static char unknown_msg[40];
7106 if (error_no >= 0 && error_no < sys_nerr)
7107 return sys_errlist[error_no];
7109 for (i = 0; _wsa_errlist[i].errnum >= 0; i++)
7110 if (_wsa_errlist[i].errnum == error_no)
7111 return _wsa_errlist[i].msg;
7113 sprintf (unknown_msg, "Unidentified error: %d", error_no);
7114 return unknown_msg;
7117 /* [andrewi 3-May-96] I've had conflicting results using both methods,
7118 but I believe the method of keeping the socket handle separate (and
7119 insuring it is not inheritable) is the correct one. */
7121 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
7123 static int socket_to_fd (SOCKET s);
7126 sys_socket (int af, int type, int protocol)
7128 SOCKET s;
7130 if (winsock_lib == NULL)
7132 errno = ENETDOWN;
7133 return INVALID_SOCKET;
7136 check_errno ();
7138 /* call the real socket function */
7139 s = pfn_socket (af, type, protocol);
7141 if (s != INVALID_SOCKET)
7142 return socket_to_fd (s);
7144 set_errno ();
7145 return -1;
7148 /* Convert a SOCKET to a file descriptor. */
7149 static int
7150 socket_to_fd (SOCKET s)
7152 int fd;
7153 child_process * cp;
7155 /* Although under NT 3.5 _open_osfhandle will accept a socket
7156 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
7157 that does not work under NT 3.1. However, we can get the same
7158 effect by using a backdoor function to replace an existing
7159 descriptor handle with the one we want. */
7161 /* allocate a file descriptor (with appropriate flags) */
7162 fd = _open ("NUL:", _O_RDWR);
7163 if (fd >= 0)
7165 /* Make a non-inheritable copy of the socket handle. Note
7166 that it is possible that sockets aren't actually kernel
7167 handles, which appears to be the case on Windows 9x when
7168 the MS Proxy winsock client is installed. */
7170 /* Apparently there is a bug in NT 3.51 with some service
7171 packs, which prevents using DuplicateHandle to make a
7172 socket handle non-inheritable (causes WSACleanup to
7173 hang). The work-around is to use SetHandleInformation
7174 instead if it is available and implemented. */
7175 if (pfn_SetHandleInformation)
7177 pfn_SetHandleInformation ((HANDLE) s, HANDLE_FLAG_INHERIT, 0);
7179 else
7181 HANDLE parent = GetCurrentProcess ();
7182 HANDLE new_s = INVALID_HANDLE_VALUE;
7184 if (DuplicateHandle (parent,
7185 (HANDLE) s,
7186 parent,
7187 &new_s,
7189 FALSE,
7190 DUPLICATE_SAME_ACCESS))
7192 /* It is possible that DuplicateHandle succeeds even
7193 though the socket wasn't really a kernel handle,
7194 because a real handle has the same value. So
7195 test whether the new handle really is a socket. */
7196 long nonblocking = 0;
7197 if (pfn_ioctlsocket ((SOCKET) new_s, FIONBIO, &nonblocking) == 0)
7199 pfn_closesocket (s);
7200 s = (SOCKET) new_s;
7202 else
7204 CloseHandle (new_s);
7209 eassert (fd < MAXDESC);
7210 fd_info[fd].hnd = (HANDLE) s;
7212 /* set our own internal flags */
7213 fd_info[fd].flags = FILE_SOCKET | FILE_BINARY | FILE_READ | FILE_WRITE;
7215 cp = new_child ();
7216 if (cp)
7218 cp->fd = fd;
7219 cp->status = STATUS_READ_ACKNOWLEDGED;
7221 /* attach child_process to fd_info */
7222 if (fd_info[ fd ].cp != NULL)
7224 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd));
7225 emacs_abort ();
7228 fd_info[ fd ].cp = cp;
7230 /* success! */
7231 winsock_inuse++; /* count open sockets */
7232 return fd;
7235 /* clean up */
7236 _close (fd);
7238 else
7239 pfn_closesocket (s);
7240 errno = EMFILE;
7241 return -1;
7245 sys_bind (int s, const struct sockaddr * addr, int namelen)
7247 if (winsock_lib == NULL)
7249 errno = ENOTSOCK;
7250 return SOCKET_ERROR;
7253 check_errno ();
7254 if (fd_info[s].flags & FILE_SOCKET)
7256 int rc = pfn_bind (SOCK_HANDLE (s), addr, namelen);
7257 if (rc == SOCKET_ERROR)
7258 set_errno ();
7259 return rc;
7261 errno = ENOTSOCK;
7262 return SOCKET_ERROR;
7266 sys_connect (int s, const struct sockaddr * name, int namelen)
7268 if (winsock_lib == NULL)
7270 errno = ENOTSOCK;
7271 return SOCKET_ERROR;
7274 check_errno ();
7275 if (fd_info[s].flags & FILE_SOCKET)
7277 int rc = pfn_connect (SOCK_HANDLE (s), name, namelen);
7278 if (rc == SOCKET_ERROR)
7279 set_errno ();
7280 return rc;
7282 errno = ENOTSOCK;
7283 return SOCKET_ERROR;
7286 u_short
7287 sys_htons (u_short hostshort)
7289 return (winsock_lib != NULL) ?
7290 pfn_htons (hostshort) : hostshort;
7293 u_short
7294 sys_ntohs (u_short netshort)
7296 return (winsock_lib != NULL) ?
7297 pfn_ntohs (netshort) : netshort;
7300 unsigned long
7301 sys_inet_addr (const char * cp)
7303 return (winsock_lib != NULL) ?
7304 pfn_inet_addr (cp) : INADDR_NONE;
7308 sys_gethostname (char * name, int namelen)
7310 if (winsock_lib != NULL)
7312 int retval;
7314 check_errno ();
7315 retval = pfn_gethostname (name, namelen);
7316 if (retval == SOCKET_ERROR)
7317 set_errno ();
7318 return retval;
7321 if (namelen > MAX_COMPUTERNAME_LENGTH)
7322 return !GetComputerName (name, (DWORD *)&namelen);
7324 errno = EFAULT;
7325 return SOCKET_ERROR;
7328 struct hostent *
7329 sys_gethostbyname (const char * name)
7331 struct hostent * host;
7332 int h_err = h_errno;
7334 if (winsock_lib == NULL)
7336 h_errno = NO_RECOVERY;
7337 errno = ENETDOWN;
7338 return NULL;
7341 check_errno ();
7342 host = pfn_gethostbyname (name);
7343 if (!host)
7345 set_errno ();
7346 h_errno = errno;
7348 else
7349 h_errno = h_err;
7350 return host;
7353 struct servent *
7354 sys_getservbyname (const char * name, const char * proto)
7356 struct servent * serv;
7358 if (winsock_lib == NULL)
7360 errno = ENETDOWN;
7361 return NULL;
7364 check_errno ();
7365 serv = pfn_getservbyname (name, proto);
7366 if (!serv)
7367 set_errno ();
7368 return serv;
7372 sys_getpeername (int s, struct sockaddr *addr, int * namelen)
7374 if (winsock_lib == NULL)
7376 errno = ENETDOWN;
7377 return SOCKET_ERROR;
7380 check_errno ();
7381 if (fd_info[s].flags & FILE_SOCKET)
7383 int rc = pfn_getpeername (SOCK_HANDLE (s), addr, namelen);
7384 if (rc == SOCKET_ERROR)
7385 set_errno ();
7386 return rc;
7388 errno = ENOTSOCK;
7389 return SOCKET_ERROR;
7393 sys_shutdown (int s, int how)
7395 if (winsock_lib == NULL)
7397 errno = ENETDOWN;
7398 return SOCKET_ERROR;
7401 check_errno ();
7402 if (fd_info[s].flags & FILE_SOCKET)
7404 int rc = pfn_shutdown (SOCK_HANDLE (s), how);
7405 if (rc == SOCKET_ERROR)
7406 set_errno ();
7407 return rc;
7409 errno = ENOTSOCK;
7410 return SOCKET_ERROR;
7414 sys_setsockopt (int s, int level, int optname, const void * optval, int optlen)
7416 if (winsock_lib == NULL)
7418 errno = ENETDOWN;
7419 return SOCKET_ERROR;
7422 check_errno ();
7423 if (fd_info[s].flags & FILE_SOCKET)
7425 int rc = pfn_setsockopt (SOCK_HANDLE (s), level, optname,
7426 (const char *)optval, optlen);
7427 if (rc == SOCKET_ERROR)
7428 set_errno ();
7429 return rc;
7431 errno = ENOTSOCK;
7432 return SOCKET_ERROR;
7436 sys_listen (int s, int backlog)
7438 if (winsock_lib == NULL)
7440 errno = ENETDOWN;
7441 return SOCKET_ERROR;
7444 check_errno ();
7445 if (fd_info[s].flags & FILE_SOCKET)
7447 int rc = pfn_listen (SOCK_HANDLE (s), backlog);
7448 if (rc == SOCKET_ERROR)
7449 set_errno ();
7450 else
7451 fd_info[s].flags |= FILE_LISTEN;
7452 return rc;
7454 errno = ENOTSOCK;
7455 return SOCKET_ERROR;
7459 sys_getsockname (int s, struct sockaddr * name, int * namelen)
7461 if (winsock_lib == NULL)
7463 errno = ENETDOWN;
7464 return SOCKET_ERROR;
7467 check_errno ();
7468 if (fd_info[s].flags & FILE_SOCKET)
7470 int rc = pfn_getsockname (SOCK_HANDLE (s), name, namelen);
7471 if (rc == SOCKET_ERROR)
7472 set_errno ();
7473 return rc;
7475 errno = ENOTSOCK;
7476 return SOCKET_ERROR;
7480 sys_accept (int s, struct sockaddr * addr, int * addrlen)
7482 if (winsock_lib == NULL)
7484 errno = ENETDOWN;
7485 return -1;
7488 check_errno ();
7489 if (fd_info[s].flags & FILE_LISTEN)
7491 SOCKET t = pfn_accept (SOCK_HANDLE (s), addr, addrlen);
7492 int fd = -1;
7493 if (t == INVALID_SOCKET)
7494 set_errno ();
7495 else
7496 fd = socket_to_fd (t);
7498 if (fd >= 0)
7500 fd_info[s].cp->status = STATUS_READ_ACKNOWLEDGED;
7501 ResetEvent (fd_info[s].cp->char_avail);
7503 return fd;
7505 errno = ENOTSOCK;
7506 return -1;
7510 sys_recvfrom (int s, char * buf, int len, int flags,
7511 struct sockaddr * from, int * fromlen)
7513 if (winsock_lib == NULL)
7515 errno = ENETDOWN;
7516 return SOCKET_ERROR;
7519 check_errno ();
7520 if (fd_info[s].flags & FILE_SOCKET)
7522 int rc = pfn_recvfrom (SOCK_HANDLE (s), buf, len, flags, from, fromlen);
7523 if (rc == SOCKET_ERROR)
7524 set_errno ();
7525 return rc;
7527 errno = ENOTSOCK;
7528 return SOCKET_ERROR;
7532 sys_sendto (int s, const char * buf, int len, int flags,
7533 const struct sockaddr * to, int tolen)
7535 if (winsock_lib == NULL)
7537 errno = ENETDOWN;
7538 return SOCKET_ERROR;
7541 check_errno ();
7542 if (fd_info[s].flags & FILE_SOCKET)
7544 int rc = pfn_sendto (SOCK_HANDLE (s), buf, len, flags, to, tolen);
7545 if (rc == SOCKET_ERROR)
7546 set_errno ();
7547 return rc;
7549 errno = ENOTSOCK;
7550 return SOCKET_ERROR;
7553 /* Windows does not have an fcntl function. Provide an implementation
7554 good enough for Emacs. */
7556 fcntl (int s, int cmd, int options)
7558 /* In the w32 Emacs port, fcntl (fd, F_DUPFD_CLOEXEC, fd1) is always
7559 invoked in a context where fd1 is closed and all descriptors less
7560 than fd1 are open, so sys_dup is an adequate implementation. */
7561 if (cmd == F_DUPFD_CLOEXEC)
7562 return sys_dup (s);
7564 if (winsock_lib == NULL)
7566 errno = ENETDOWN;
7567 return -1;
7570 check_errno ();
7571 if (fd_info[s].flags & FILE_SOCKET)
7573 if (cmd == F_SETFL && options == O_NONBLOCK)
7575 unsigned long nblock = 1;
7576 int rc = pfn_ioctlsocket (SOCK_HANDLE (s), FIONBIO, &nblock);
7577 if (rc == SOCKET_ERROR)
7578 set_errno ();
7579 /* Keep track of the fact that we set this to non-blocking. */
7580 fd_info[s].flags |= FILE_NDELAY;
7581 return rc;
7583 else
7585 errno = EINVAL;
7586 return SOCKET_ERROR;
7589 errno = ENOTSOCK;
7590 return SOCKET_ERROR;
7594 /* Shadow main io functions: we need to handle pipes and sockets more
7595 intelligently, and implement non-blocking mode as well. */
7598 sys_close (int fd)
7600 int rc;
7602 if (fd < 0)
7604 errno = EBADF;
7605 return -1;
7608 if (fd < MAXDESC && fd_info[fd].cp)
7610 child_process * cp = fd_info[fd].cp;
7612 fd_info[fd].cp = NULL;
7614 if (CHILD_ACTIVE (cp))
7616 /* if last descriptor to active child_process then cleanup */
7617 int i;
7618 for (i = 0; i < MAXDESC; i++)
7620 if (i == fd)
7621 continue;
7622 if (fd_info[i].cp == cp)
7623 break;
7625 if (i == MAXDESC)
7627 if (fd_info[fd].flags & FILE_SOCKET)
7629 if (winsock_lib == NULL) emacs_abort ();
7631 pfn_shutdown (SOCK_HANDLE (fd), 2);
7632 rc = pfn_closesocket (SOCK_HANDLE (fd));
7634 winsock_inuse--; /* count open sockets */
7636 /* If the process handle is NULL, it's either a socket
7637 or serial connection, or a subprocess that was
7638 already reaped by reap_subprocess, but whose
7639 resources were not yet freed, because its output was
7640 not fully read yet by the time it was reaped. (This
7641 usually happens with async subprocesses whose output
7642 is being read by Emacs.) Otherwise, this process was
7643 not reaped yet, so we set its FD to a negative value
7644 to make sure sys_select will eventually get to
7645 calling the SIGCHLD handler for it, which will then
7646 invoke waitpid and reap_subprocess. */
7647 if (cp->procinfo.hProcess == NULL)
7648 delete_child (cp);
7649 else
7650 cp->fd = -1;
7655 if (fd >= 0 && fd < MAXDESC)
7656 fd_info[fd].flags = 0;
7658 /* Note that sockets do not need special treatment here (at least on
7659 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
7660 closesocket is equivalent to CloseHandle, which is to be expected
7661 because socket handles are fully fledged kernel handles. */
7662 rc = _close (fd);
7664 return rc;
7668 sys_dup (int fd)
7670 int new_fd;
7672 new_fd = _dup (fd);
7673 if (new_fd >= 0 && new_fd < MAXDESC)
7675 /* duplicate our internal info as well */
7676 fd_info[new_fd] = fd_info[fd];
7678 return new_fd;
7682 sys_dup2 (int src, int dst)
7684 int rc;
7686 if (dst < 0 || dst >= MAXDESC)
7688 errno = EBADF;
7689 return -1;
7692 /* make sure we close the destination first if it's a pipe or socket */
7693 if (src != dst && fd_info[dst].flags != 0)
7694 sys_close (dst);
7696 rc = _dup2 (src, dst);
7697 if (rc == 0)
7699 /* duplicate our internal info as well */
7700 fd_info[dst] = fd_info[src];
7702 return rc;
7706 pipe2 (int * phandles, int pipe2_flags)
7708 int rc;
7709 unsigned flags;
7711 eassert (pipe2_flags == O_CLOEXEC);
7713 /* make pipe handles non-inheritable; when we spawn a child, we
7714 replace the relevant handle with an inheritable one. Also put
7715 pipes into binary mode; we will do text mode translation ourselves
7716 if required. */
7717 rc = _pipe (phandles, 0, _O_NOINHERIT | _O_BINARY);
7719 if (rc == 0)
7721 /* Protect against overflow, since Windows can open more handles than
7722 our fd_info array has room for. */
7723 if (phandles[0] >= MAXDESC || phandles[1] >= MAXDESC)
7725 _close (phandles[0]);
7726 _close (phandles[1]);
7727 errno = EMFILE;
7728 rc = -1;
7730 else
7732 flags = FILE_PIPE | FILE_READ | FILE_BINARY;
7733 fd_info[phandles[0]].flags = flags;
7735 flags = FILE_PIPE | FILE_WRITE | FILE_BINARY;
7736 fd_info[phandles[1]].flags = flags;
7740 return rc;
7743 /* Function to do blocking read of one byte, needed to implement
7744 select. It is only allowed on communication ports, sockets, or
7745 pipes. */
7747 _sys_read_ahead (int fd)
7749 child_process * cp;
7750 int rc;
7752 if (fd < 0 || fd >= MAXDESC)
7753 return STATUS_READ_ERROR;
7755 cp = fd_info[fd].cp;
7757 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
7758 return STATUS_READ_ERROR;
7760 if ((fd_info[fd].flags & (FILE_PIPE | FILE_SERIAL | FILE_SOCKET)) == 0
7761 || (fd_info[fd].flags & FILE_READ) == 0)
7763 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd));
7764 emacs_abort ();
7767 cp->status = STATUS_READ_IN_PROGRESS;
7769 if (fd_info[fd].flags & FILE_PIPE)
7771 rc = _read (fd, &cp->chr, sizeof (char));
7773 /* Give subprocess time to buffer some more output for us before
7774 reporting that input is available; we need this because Windows 95
7775 connects DOS programs to pipes by making the pipe appear to be
7776 the normal console stdout - as a result most DOS programs will
7777 write to stdout without buffering, ie. one character at a
7778 time. Even some W32 programs do this - "dir" in a command
7779 shell on NT is very slow if we don't do this. */
7780 if (rc > 0)
7782 int wait = w32_pipe_read_delay;
7784 if (wait > 0)
7785 Sleep (wait);
7786 else if (wait < 0)
7787 while (++wait <= 0)
7788 /* Yield remainder of our time slice, effectively giving a
7789 temporary priority boost to the child process. */
7790 Sleep (0);
7793 else if (fd_info[fd].flags & FILE_SERIAL)
7795 HANDLE hnd = fd_info[fd].hnd;
7796 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
7797 COMMTIMEOUTS ct;
7799 /* Configure timeouts for blocking read. */
7800 if (!GetCommTimeouts (hnd, &ct))
7802 cp->status = STATUS_READ_ERROR;
7803 return STATUS_READ_ERROR;
7805 ct.ReadIntervalTimeout = 0;
7806 ct.ReadTotalTimeoutMultiplier = 0;
7807 ct.ReadTotalTimeoutConstant = 0;
7808 if (!SetCommTimeouts (hnd, &ct))
7810 cp->status = STATUS_READ_ERROR;
7811 return STATUS_READ_ERROR;
7814 if (!ReadFile (hnd, &cp->chr, sizeof (char), (DWORD*) &rc, ovl))
7816 if (GetLastError () != ERROR_IO_PENDING)
7818 cp->status = STATUS_READ_ERROR;
7819 return STATUS_READ_ERROR;
7821 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
7823 cp->status = STATUS_READ_ERROR;
7824 return STATUS_READ_ERROR;
7828 else if (fd_info[fd].flags & FILE_SOCKET)
7830 unsigned long nblock = 0;
7831 /* We always want this to block, so temporarily disable NDELAY. */
7832 if (fd_info[fd].flags & FILE_NDELAY)
7833 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
7835 rc = pfn_recv (SOCK_HANDLE (fd), &cp->chr, sizeof (char), 0);
7837 if (fd_info[fd].flags & FILE_NDELAY)
7839 nblock = 1;
7840 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
7844 if (rc == sizeof (char))
7845 cp->status = STATUS_READ_SUCCEEDED;
7846 else
7847 cp->status = STATUS_READ_FAILED;
7849 return cp->status;
7853 _sys_wait_accept (int fd)
7855 HANDLE hEv;
7856 child_process * cp;
7857 int rc;
7859 if (fd < 0 || fd >= MAXDESC)
7860 return STATUS_READ_ERROR;
7862 cp = fd_info[fd].cp;
7864 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
7865 return STATUS_READ_ERROR;
7867 cp->status = STATUS_READ_FAILED;
7869 hEv = pfn_WSACreateEvent ();
7870 rc = pfn_WSAEventSelect (SOCK_HANDLE (fd), hEv, FD_ACCEPT);
7871 if (rc != SOCKET_ERROR)
7873 do {
7874 rc = WaitForSingleObject (hEv, 500);
7875 Sleep (5);
7876 } while (rc == WAIT_TIMEOUT
7877 && cp->status != STATUS_READ_ERROR
7878 && cp->char_avail);
7879 pfn_WSAEventSelect (SOCK_HANDLE (fd), NULL, 0);
7880 if (rc == WAIT_OBJECT_0)
7881 cp->status = STATUS_READ_SUCCEEDED;
7883 pfn_WSACloseEvent (hEv);
7885 return cp->status;
7889 sys_read (int fd, char * buffer, unsigned int count)
7891 int nchars;
7892 int to_read;
7893 DWORD waiting;
7894 char * orig_buffer = buffer;
7896 if (fd < 0)
7898 errno = EBADF;
7899 return -1;
7902 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
7904 child_process *cp = fd_info[fd].cp;
7906 if ((fd_info[fd].flags & FILE_READ) == 0)
7908 errno = EBADF;
7909 return -1;
7912 nchars = 0;
7914 /* re-read CR carried over from last read */
7915 if (fd_info[fd].flags & FILE_LAST_CR)
7917 if (fd_info[fd].flags & FILE_BINARY) emacs_abort ();
7918 *buffer++ = 0x0d;
7919 count--;
7920 nchars++;
7921 fd_info[fd].flags &= ~FILE_LAST_CR;
7924 /* presence of a child_process structure means we are operating in
7925 non-blocking mode - otherwise we just call _read directly.
7926 Note that the child_process structure might be missing because
7927 reap_subprocess has been called; in this case the pipe is
7928 already broken, so calling _read on it is okay. */
7929 if (cp)
7931 int current_status = cp->status;
7933 switch (current_status)
7935 case STATUS_READ_FAILED:
7936 case STATUS_READ_ERROR:
7937 /* report normal EOF if nothing in buffer */
7938 if (nchars <= 0)
7939 fd_info[fd].flags |= FILE_AT_EOF;
7940 return nchars;
7942 case STATUS_READ_READY:
7943 case STATUS_READ_IN_PROGRESS:
7944 DebPrint (("sys_read called when read is in progress\n"));
7945 errno = EWOULDBLOCK;
7946 return -1;
7948 case STATUS_READ_SUCCEEDED:
7949 /* consume read-ahead char */
7950 *buffer++ = cp->chr;
7951 count--;
7952 nchars++;
7953 cp->status = STATUS_READ_ACKNOWLEDGED;
7954 ResetEvent (cp->char_avail);
7956 case STATUS_READ_ACKNOWLEDGED:
7957 break;
7959 default:
7960 DebPrint (("sys_read: bad status %d\n", current_status));
7961 errno = EBADF;
7962 return -1;
7965 if (fd_info[fd].flags & FILE_PIPE)
7967 PeekNamedPipe ((HANDLE) _get_osfhandle (fd), NULL, 0, NULL, &waiting, NULL);
7968 to_read = min (waiting, (DWORD) count);
7970 if (to_read > 0)
7971 nchars += _read (fd, buffer, to_read);
7973 else if (fd_info[fd].flags & FILE_SERIAL)
7975 HANDLE hnd = fd_info[fd].hnd;
7976 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
7977 int rc = 0;
7978 COMMTIMEOUTS ct;
7980 if (count > 0)
7982 /* Configure timeouts for non-blocking read. */
7983 if (!GetCommTimeouts (hnd, &ct))
7985 errno = EIO;
7986 return -1;
7988 ct.ReadIntervalTimeout = MAXDWORD;
7989 ct.ReadTotalTimeoutMultiplier = 0;
7990 ct.ReadTotalTimeoutConstant = 0;
7991 if (!SetCommTimeouts (hnd, &ct))
7993 errno = EIO;
7994 return -1;
7997 if (!ResetEvent (ovl->hEvent))
7999 errno = EIO;
8000 return -1;
8002 if (!ReadFile (hnd, buffer, count, (DWORD*) &rc, ovl))
8004 if (GetLastError () != ERROR_IO_PENDING)
8006 errno = EIO;
8007 return -1;
8009 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
8011 errno = EIO;
8012 return -1;
8015 nchars += rc;
8018 else /* FILE_SOCKET */
8020 if (winsock_lib == NULL) emacs_abort ();
8022 /* do the equivalent of a non-blocking read */
8023 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONREAD, &waiting);
8024 if (waiting == 0 && nchars == 0)
8026 errno = EWOULDBLOCK;
8027 return -1;
8030 if (waiting)
8032 /* always use binary mode for sockets */
8033 int res = pfn_recv (SOCK_HANDLE (fd), buffer, count, 0);
8034 if (res == SOCKET_ERROR)
8036 DebPrint (("sys_read.recv failed with error %d on socket %ld\n",
8037 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
8038 set_errno ();
8039 return -1;
8041 nchars += res;
8045 else
8047 int nread = _read (fd, buffer, count);
8048 if (nread >= 0)
8049 nchars += nread;
8050 else if (nchars == 0)
8051 nchars = nread;
8054 if (nchars <= 0)
8055 fd_info[fd].flags |= FILE_AT_EOF;
8056 /* Perform text mode translation if required. */
8057 else if ((fd_info[fd].flags & FILE_BINARY) == 0)
8059 nchars = crlf_to_lf (nchars, orig_buffer);
8060 /* If buffer contains only CR, return that. To be absolutely
8061 sure we should attempt to read the next char, but in
8062 practice a CR to be followed by LF would not appear by
8063 itself in the buffer. */
8064 if (nchars > 1 && orig_buffer[nchars - 1] == 0x0d)
8066 fd_info[fd].flags |= FILE_LAST_CR;
8067 nchars--;
8071 else
8072 nchars = _read (fd, buffer, count);
8074 return nchars;
8077 /* From w32xfns.c */
8078 extern HANDLE interrupt_handle;
8080 /* For now, don't bother with a non-blocking mode */
8082 sys_write (int fd, const void * buffer, unsigned int count)
8084 int nchars;
8086 if (fd < 0)
8088 errno = EBADF;
8089 return -1;
8092 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
8094 if ((fd_info[fd].flags & FILE_WRITE) == 0)
8096 errno = EBADF;
8097 return -1;
8100 /* Perform text mode translation if required. */
8101 if ((fd_info[fd].flags & FILE_BINARY) == 0)
8103 char * tmpbuf = alloca (count * 2);
8104 unsigned char * src = (void *)buffer;
8105 unsigned char * dst = tmpbuf;
8106 int nbytes = count;
8108 while (1)
8110 unsigned char *next;
8111 /* copy next line or remaining bytes */
8112 next = _memccpy (dst, src, '\n', nbytes);
8113 if (next)
8115 /* copied one line ending with '\n' */
8116 int copied = next - dst;
8117 nbytes -= copied;
8118 src += copied;
8119 /* insert '\r' before '\n' */
8120 next[-1] = '\r';
8121 next[0] = '\n';
8122 dst = next + 1;
8123 count++;
8125 else
8126 /* copied remaining partial line -> now finished */
8127 break;
8129 buffer = tmpbuf;
8133 if (fd < MAXDESC && fd_info[fd].flags & FILE_SERIAL)
8135 HANDLE hnd = (HANDLE) _get_osfhandle (fd);
8136 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_write;
8137 HANDLE wait_hnd[2] = { interrupt_handle, ovl->hEvent };
8138 DWORD active = 0;
8140 if (!WriteFile (hnd, buffer, count, (DWORD*) &nchars, ovl))
8142 if (GetLastError () != ERROR_IO_PENDING)
8144 errno = EIO;
8145 return -1;
8147 if (detect_input_pending ())
8148 active = MsgWaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE,
8149 QS_ALLINPUT);
8150 else
8151 active = WaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE);
8152 if (active == WAIT_OBJECT_0)
8153 { /* User pressed C-g, cancel write, then leave. Don't bother
8154 cleaning up as we may only get stuck in buggy drivers. */
8155 PurgeComm (hnd, PURGE_TXABORT | PURGE_TXCLEAR);
8156 CancelIo (hnd);
8157 errno = EIO;
8158 return -1;
8160 if (active == WAIT_OBJECT_0 + 1
8161 && !GetOverlappedResult (hnd, ovl, (DWORD*) &nchars, TRUE))
8163 errno = EIO;
8164 return -1;
8168 else if (fd < MAXDESC && fd_info[fd].flags & FILE_SOCKET)
8170 unsigned long nblock = 0;
8171 if (winsock_lib == NULL) emacs_abort ();
8173 /* TODO: implement select() properly so non-blocking I/O works. */
8174 /* For now, make sure the write blocks. */
8175 if (fd_info[fd].flags & FILE_NDELAY)
8176 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
8178 nchars = pfn_send (SOCK_HANDLE (fd), buffer, count, 0);
8180 /* Set the socket back to non-blocking if it was before,
8181 for other operations that support it. */
8182 if (fd_info[fd].flags & FILE_NDELAY)
8184 nblock = 1;
8185 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
8188 if (nchars == SOCKET_ERROR)
8190 DebPrint (("sys_write.send failed with error %d on socket %ld\n",
8191 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
8192 set_errno ();
8195 else
8197 /* Some networked filesystems don't like too large writes, so
8198 break them into smaller chunks. See the Comments section of
8199 the MSDN documentation of WriteFile for details behind the
8200 choice of the value of CHUNK below. See also the thread
8201 http://thread.gmane.org/gmane.comp.version-control.git/145294
8202 in the git mailing list. */
8203 const unsigned char *p = buffer;
8204 const unsigned chunk = 30 * 1024 * 1024;
8206 nchars = 0;
8207 while (count > 0)
8209 unsigned this_chunk = count < chunk ? count : chunk;
8210 int n = _write (fd, p, this_chunk);
8212 nchars += n;
8213 if (n < 0)
8215 nchars = n;
8216 break;
8218 else if (n < this_chunk)
8219 break;
8220 count -= n;
8221 p += n;
8225 return nchars;
8229 /* Emulation of SIOCGIFCONF and getifaddrs, see process.c. */
8231 extern Lisp_Object conv_sockaddr_to_lisp (struct sockaddr *, int);
8233 /* Return information about network interface IFNAME, or about all
8234 interfaces (if IFNAME is nil). */
8235 static Lisp_Object
8236 network_interface_get_info (Lisp_Object ifname)
8238 ULONG ainfo_len = sizeof (IP_ADAPTER_INFO);
8239 IP_ADAPTER_INFO *adapter, *ainfo = xmalloc (ainfo_len);
8240 DWORD retval = get_adapters_info (ainfo, &ainfo_len);
8241 Lisp_Object res = Qnil;
8243 if (retval == ERROR_BUFFER_OVERFLOW)
8245 ainfo = xrealloc (ainfo, ainfo_len);
8246 retval = get_adapters_info (ainfo, &ainfo_len);
8249 if (retval == ERROR_SUCCESS)
8251 int eth_count = 0, tr_count = 0, fddi_count = 0, ppp_count = 0;
8252 int sl_count = 0, wlan_count = 0, lo_count = 0, ifx_count = 0;
8253 int if_num;
8254 struct sockaddr_in sa;
8256 /* For the below, we need some winsock functions, so make sure
8257 the winsock DLL is loaded. If we cannot successfully load
8258 it, they will have no use of the information we provide,
8259 anyway, so punt. */
8260 if (!winsock_lib && !init_winsock (1))
8261 goto done;
8263 for (adapter = ainfo; adapter; adapter = adapter->Next)
8265 char namebuf[MAX_ADAPTER_NAME_LENGTH + 4];
8266 u_long ip_addr;
8267 /* Present Unix-compatible interface names, instead of the
8268 Windows names, which are really GUIDs not readable by
8269 humans. */
8270 static const char *ifmt[] = {
8271 "eth%d", "tr%d", "fddi%d", "ppp%d", "sl%d", "wlan%d",
8272 "lo", "ifx%d"
8274 enum {
8275 NONE = -1,
8276 ETHERNET = 0,
8277 TOKENRING = 1,
8278 FDDI = 2,
8279 PPP = 3,
8280 SLIP = 4,
8281 WLAN = 5,
8282 LOOPBACK = 6,
8283 OTHER_IF = 7
8284 } ifmt_idx;
8286 switch (adapter->Type)
8288 case MIB_IF_TYPE_ETHERNET:
8289 /* Windows before Vista reports wireless adapters as
8290 Ethernet. Work around by looking at the Description
8291 string. */
8292 if (strstr (adapter->Description, "Wireless "))
8294 ifmt_idx = WLAN;
8295 if_num = wlan_count++;
8297 else
8299 ifmt_idx = ETHERNET;
8300 if_num = eth_count++;
8302 break;
8303 case MIB_IF_TYPE_TOKENRING:
8304 ifmt_idx = TOKENRING;
8305 if_num = tr_count++;
8306 break;
8307 case MIB_IF_TYPE_FDDI:
8308 ifmt_idx = FDDI;
8309 if_num = fddi_count++;
8310 break;
8311 case MIB_IF_TYPE_PPP:
8312 ifmt_idx = PPP;
8313 if_num = ppp_count++;
8314 break;
8315 case MIB_IF_TYPE_SLIP:
8316 ifmt_idx = SLIP;
8317 if_num = sl_count++;
8318 break;
8319 case IF_TYPE_IEEE80211:
8320 ifmt_idx = WLAN;
8321 if_num = wlan_count++;
8322 break;
8323 case MIB_IF_TYPE_LOOPBACK:
8324 if (lo_count < 0)
8326 ifmt_idx = LOOPBACK;
8327 if_num = lo_count++;
8329 else
8330 ifmt_idx = NONE;
8331 break;
8332 default:
8333 ifmt_idx = OTHER_IF;
8334 if_num = ifx_count++;
8335 break;
8337 if (ifmt_idx == NONE)
8338 continue;
8339 sprintf (namebuf, ifmt[ifmt_idx], if_num);
8341 sa.sin_family = AF_INET;
8342 ip_addr = sys_inet_addr (adapter->IpAddressList.IpAddress.String);
8343 if (ip_addr == INADDR_NONE)
8345 /* Bogus address, skip this interface. */
8346 continue;
8348 sa.sin_addr.s_addr = ip_addr;
8349 sa.sin_port = 0;
8350 if (NILP (ifname))
8351 res = Fcons (Fcons (build_string (namebuf),
8352 conv_sockaddr_to_lisp ((struct sockaddr*) &sa,
8353 sizeof (struct sockaddr))),
8354 res);
8355 else if (strcmp (namebuf, SSDATA (ifname)) == 0)
8357 Lisp_Object hwaddr = Fmake_vector (make_number (6), Qnil);
8358 register struct Lisp_Vector *p = XVECTOR (hwaddr);
8359 Lisp_Object flags = Qnil;
8360 int n;
8361 u_long net_mask;
8363 /* Flags. We guess most of them by type, since the
8364 Windows flags are different and hard to get by. */
8365 flags = Fcons (intern ("up"), flags);
8366 if (ifmt_idx == ETHERNET || ifmt_idx == WLAN)
8368 flags = Fcons (intern ("broadcast"), flags);
8369 flags = Fcons (intern ("multicast"), flags);
8371 flags = Fcons (intern ("running"), flags);
8372 if (ifmt_idx == PPP)
8374 flags = Fcons (intern ("pointopoint"), flags);
8375 flags = Fcons (intern ("noarp"), flags);
8377 if (adapter->HaveWins)
8378 flags = Fcons (intern ("WINS"), flags);
8379 if (adapter->DhcpEnabled)
8380 flags = Fcons (intern ("dynamic"), flags);
8382 res = Fcons (flags, res);
8384 /* Hardware address and its family. */
8385 for (n = 0; n < adapter->AddressLength; n++)
8386 p->contents[n] = make_number ((int) adapter->Address[n]);
8387 /* Windows does not support AF_LINK or AF_PACKET family
8388 of addresses. Use an arbitrary family number that is
8389 identical to what GNU/Linux returns. */
8390 res = Fcons (Fcons (make_number (1), hwaddr), res);
8392 /* Network mask. */
8393 sa.sin_family = AF_INET;
8394 net_mask = sys_inet_addr (adapter->IpAddressList.IpMask.String);
8395 if (net_mask != INADDR_NONE)
8397 sa.sin_addr.s_addr = net_mask;
8398 sa.sin_port = 0;
8399 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
8400 sizeof (struct sockaddr)),
8401 res);
8403 else
8404 res = Fcons (Qnil, res);
8406 sa.sin_family = AF_INET;
8407 if (ip_addr != INADDR_NONE)
8409 /* Broadcast address is only reported by
8410 GetAdaptersAddresses, which is of limited
8411 availability. Generate it on our own. */
8412 u_long bcast_addr = (ip_addr & net_mask) | ~net_mask;
8414 sa.sin_addr.s_addr = bcast_addr;
8415 sa.sin_port = 0;
8416 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
8417 sizeof (struct sockaddr)),
8418 res);
8420 /* IP address. */
8421 sa.sin_addr.s_addr = ip_addr;
8422 sa.sin_port = 0;
8423 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
8424 sizeof (struct sockaddr)),
8425 res);
8427 else
8428 res = Fcons (Qnil, Fcons (Qnil, res));
8431 /* GetAdaptersInfo is documented to not report loopback
8432 interfaces, so we generate one out of thin air. */
8433 if (!lo_count)
8435 sa.sin_family = AF_INET;
8436 sa.sin_port = 0;
8437 if (NILP (ifname))
8439 sa.sin_addr.s_addr = sys_inet_addr ("127.0.0.1");
8440 res = Fcons (Fcons (build_string ("lo"),
8441 conv_sockaddr_to_lisp ((struct sockaddr*) &sa,
8442 sizeof (struct sockaddr))),
8443 res);
8445 else if (strcmp (SSDATA (ifname), "lo") == 0)
8447 res = Fcons (Fcons (intern ("running"),
8448 Fcons (intern ("loopback"),
8449 Fcons (intern ("up"), Qnil))), Qnil);
8450 /* 772 is what 3 different GNU/Linux systems report for
8451 the loopback interface. */
8452 res = Fcons (Fcons (make_number (772),
8453 Fmake_vector (make_number (6),
8454 make_number (0))),
8455 res);
8456 sa.sin_addr.s_addr = sys_inet_addr ("255.0.0.0");
8457 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
8458 sizeof (struct sockaddr)),
8459 res);
8460 sa.sin_addr.s_addr = sys_inet_addr ("0.0.0.0");
8461 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
8462 sizeof (struct sockaddr)),
8463 res);
8464 sa.sin_addr.s_addr = sys_inet_addr ("127.0.0.1");
8465 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
8466 sizeof (struct sockaddr)),
8467 res);
8473 done:
8474 xfree (ainfo);
8475 return res;
8478 Lisp_Object
8479 network_interface_list (void)
8481 return network_interface_get_info (Qnil);
8484 Lisp_Object
8485 network_interface_info (Lisp_Object ifname)
8487 return network_interface_get_info (ifname);
8491 /* The Windows CRT functions are "optimized for speed", so they don't
8492 check for timezone and DST changes if they were last called less
8493 than 1 minute ago (see http://support.microsoft.com/kb/821231). So
8494 all Emacs features that repeatedly call time functions (e.g.,
8495 display-time) are in real danger of missing timezone and DST
8496 changes. Calling tzset before each localtime call fixes that. */
8497 struct tm *
8498 sys_localtime (const time_t *t)
8500 tzset ();
8501 return localtime (t);
8506 /* Try loading LIBRARY_ID from the file(s) specified in
8507 Vdynamic_library_alist. If the library is loaded successfully,
8508 return the handle of the DLL, and record the filename in the
8509 property :loaded-from of LIBRARY_ID. If the library could not be
8510 found, or when it was already loaded (because the handle is not
8511 recorded anywhere, and so is lost after use), return NULL.
8513 We could also save the handle in :loaded-from, but currently
8514 there's no use case for it. */
8515 HMODULE
8516 w32_delayed_load (Lisp_Object library_id)
8518 HMODULE dll_handle = NULL;
8520 CHECK_SYMBOL (library_id);
8522 if (CONSP (Vdynamic_library_alist)
8523 && NILP (Fassq (library_id, Vlibrary_cache)))
8525 Lisp_Object found = Qnil;
8526 Lisp_Object dlls = Fassq (library_id, Vdynamic_library_alist);
8528 if (CONSP (dlls))
8529 for (dlls = XCDR (dlls); CONSP (dlls); dlls = XCDR (dlls))
8531 Lisp_Object dll = XCAR (dlls);
8532 char name[MAX_UTF8_PATH];
8533 DWORD res = -1;
8535 CHECK_STRING (dll);
8536 dll = ENCODE_FILE (dll);
8537 if (w32_unicode_filenames)
8539 wchar_t name_w[MAX_PATH];
8541 filename_to_utf16 (SSDATA (dll), name_w);
8542 dll_handle = LoadLibraryW (name_w);
8543 if (dll_handle)
8545 res = GetModuleFileNameW (dll_handle, name_w,
8546 sizeof (name_w));
8547 if (res > 0)
8548 filename_from_utf16 (name_w, name);
8551 else
8553 char name_a[MAX_PATH];
8555 filename_to_ansi (SSDATA (dll), name_a);
8556 dll_handle = LoadLibraryA (name_a);
8557 if (dll_handle)
8559 res = GetModuleFileNameA (dll_handle, name_a,
8560 sizeof (name_a));
8561 if (res > 0)
8562 filename_from_ansi (name_a, name);
8565 if (dll_handle)
8567 ptrdiff_t len = strlen (name);
8568 found = Fcons (dll,
8569 (res > 0)
8570 /* Possibly truncated */
8571 ? make_specified_string (name, -1, len, 1)
8572 : Qnil);
8573 break;
8577 Fput (library_id, QCloaded_from, found);
8580 return dll_handle;
8584 void
8585 check_windows_init_file (void)
8587 /* A common indication that Emacs is not installed properly is when
8588 it cannot find the Windows installation file. If this file does
8589 not exist in the expected place, tell the user. */
8591 if (!noninteractive && !inhibit_window_system
8592 /* Vload_path is not yet initialized when we are loading
8593 loadup.el. */
8594 && NILP (Vpurify_flag))
8596 Lisp_Object init_file;
8597 int fd;
8599 /* Implementation note: this function runs early during Emacs
8600 startup, before startup.el is run. So Vload_path is still in
8601 its initial unibyte form, but it holds UTF-8 encoded file
8602 names, since init_callproc was already called. So we do not
8603 need to ENCODE_FILE here, but we do need to convert the file
8604 names from UTF-8 to ANSI. */
8605 init_file = build_string ("term/w32-win");
8606 fd = openp (Vload_path, init_file, Fget_load_suffixes (), NULL, Qnil, 0);
8607 if (fd < 0)
8609 Lisp_Object load_path_print = Fprin1_to_string (Vload_path, Qnil);
8610 char *init_file_name = SDATA (init_file);
8611 char *load_path = SDATA (load_path_print);
8612 char *buffer = alloca (1024
8613 + strlen (init_file_name)
8614 + strlen (load_path));
8615 char *msg = buffer;
8616 int needed;
8618 sprintf (buffer,
8619 "The Emacs Windows initialization file \"%s.el\" "
8620 "could not be found in your Emacs installation. "
8621 "Emacs checked the following directories for this file:\n"
8622 "\n%s\n\n"
8623 "When Emacs cannot find this file, it usually means that it "
8624 "was not installed properly, or its distribution file was "
8625 "not unpacked properly.\nSee the README.W32 file in the "
8626 "top-level Emacs directory for more information.",
8627 init_file_name, load_path);
8628 needed = MultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, buffer,
8629 -1, NULL, 0);
8630 if (needed > 0)
8632 wchar_t *msg_w = alloca ((needed + 1) * sizeof (wchar_t));
8634 MultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, buffer, -1,
8635 msg_w, needed);
8636 needed = WideCharToMultiByte (CP_ACP, 0, msg_w, -1,
8637 NULL, 0, NULL, NULL);
8638 if (needed > 0)
8640 char *msg_a = alloca (needed + 1);
8642 WideCharToMultiByte (CP_ACP, 0, msg_w, -1, msg_a, needed,
8643 NULL, NULL);
8644 msg = msg_a;
8647 MessageBox (NULL,
8648 msg,
8649 "Emacs Abort Dialog",
8650 MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
8651 /* Use the low-level system abort. */
8652 abort ();
8654 else
8656 _close (fd);
8661 void
8662 term_ntproc (int ignored)
8664 (void)ignored;
8666 term_timers ();
8668 /* shutdown the socket interface if necessary */
8669 term_winsock ();
8671 term_w32select ();
8674 void
8675 init_ntproc (int dumping)
8677 sigset_t initial_mask = 0;
8679 /* Initialize the socket interface now if available and requested by
8680 the user by defining PRELOAD_WINSOCK; otherwise loading will be
8681 delayed until open-network-stream is called (w32-has-winsock can
8682 also be used to dynamically load or reload winsock).
8684 Conveniently, init_environment is called before us, so
8685 PRELOAD_WINSOCK can be set in the registry. */
8687 /* Always initialize this correctly. */
8688 winsock_lib = NULL;
8690 if (getenv ("PRELOAD_WINSOCK") != NULL)
8691 init_winsock (TRUE);
8693 /* Initial preparation for subprocess support: replace our standard
8694 handles with non-inheritable versions. */
8696 HANDLE parent;
8697 HANDLE stdin_save = INVALID_HANDLE_VALUE;
8698 HANDLE stdout_save = INVALID_HANDLE_VALUE;
8699 HANDLE stderr_save = INVALID_HANDLE_VALUE;
8701 parent = GetCurrentProcess ();
8703 /* ignore errors when duplicating and closing; typically the
8704 handles will be invalid when running as a gui program. */
8705 DuplicateHandle (parent,
8706 GetStdHandle (STD_INPUT_HANDLE),
8707 parent,
8708 &stdin_save,
8710 FALSE,
8711 DUPLICATE_SAME_ACCESS);
8713 DuplicateHandle (parent,
8714 GetStdHandle (STD_OUTPUT_HANDLE),
8715 parent,
8716 &stdout_save,
8718 FALSE,
8719 DUPLICATE_SAME_ACCESS);
8721 DuplicateHandle (parent,
8722 GetStdHandle (STD_ERROR_HANDLE),
8723 parent,
8724 &stderr_save,
8726 FALSE,
8727 DUPLICATE_SAME_ACCESS);
8729 fclose (stdin);
8730 fclose (stdout);
8731 fclose (stderr);
8733 if (stdin_save != INVALID_HANDLE_VALUE)
8734 _open_osfhandle ((intptr_t) stdin_save, O_TEXT);
8735 else
8736 _open ("nul", O_TEXT | O_NOINHERIT | O_RDONLY);
8737 _fdopen (0, "r");
8739 if (stdout_save != INVALID_HANDLE_VALUE)
8740 _open_osfhandle ((intptr_t) stdout_save, O_TEXT);
8741 else
8742 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
8743 _fdopen (1, "w");
8745 if (stderr_save != INVALID_HANDLE_VALUE)
8746 _open_osfhandle ((intptr_t) stderr_save, O_TEXT);
8747 else
8748 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
8749 _fdopen (2, "w");
8752 /* unfortunately, atexit depends on implementation of malloc */
8753 /* atexit (term_ntproc); */
8754 if (!dumping)
8756 /* Make sure we start with all signals unblocked. */
8757 sigprocmask (SIG_SETMASK, &initial_mask, NULL);
8758 signal (SIGABRT, term_ntproc);
8760 init_timers ();
8762 /* determine which drives are fixed, for GetCachedVolumeInformation */
8764 /* GetDriveType must have trailing backslash. */
8765 char drive[] = "A:\\";
8767 /* Loop over all possible drive letters */
8768 while (*drive <= 'Z')
8770 /* Record if this drive letter refers to a fixed drive. */
8771 fixed_drives[DRIVE_INDEX (*drive)] =
8772 (GetDriveType (drive) == DRIVE_FIXED);
8774 (*drive)++;
8777 /* Reset the volume info cache. */
8778 volume_cache = NULL;
8783 shutdown_handler ensures that buffers' autosave files are
8784 up to date when the user logs off, or the system shuts down.
8786 static BOOL WINAPI
8787 shutdown_handler (DWORD type)
8789 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
8790 if (type == CTRL_CLOSE_EVENT /* User closes console window. */
8791 || type == CTRL_LOGOFF_EVENT /* User logs off. */
8792 || type == CTRL_SHUTDOWN_EVENT) /* User shutsdown. */
8794 /* Shut down cleanly, making sure autosave files are up to date. */
8795 shut_down_emacs (0, Qnil);
8798 /* Allow other handlers to handle this signal. */
8799 return FALSE;
8803 globals_of_w32 is used to initialize those global variables that
8804 must always be initialized on startup even when the global variable
8805 initialized is non zero (see the function main in emacs.c).
8807 void
8808 globals_of_w32 (void)
8810 HMODULE kernel32 = GetModuleHandle ("kernel32.dll");
8812 get_process_times_fn = (GetProcessTimes_Proc)
8813 GetProcAddress (kernel32, "GetProcessTimes");
8815 DEFSYM (QCloaded_from, ":loaded-from");
8817 g_b_init_is_windows_9x = 0;
8818 g_b_init_open_process_token = 0;
8819 g_b_init_get_token_information = 0;
8820 g_b_init_lookup_account_sid = 0;
8821 g_b_init_get_sid_sub_authority = 0;
8822 g_b_init_get_sid_sub_authority_count = 0;
8823 g_b_init_get_security_info = 0;
8824 g_b_init_get_file_security_w = 0;
8825 g_b_init_get_file_security_a = 0;
8826 g_b_init_get_security_descriptor_owner = 0;
8827 g_b_init_get_security_descriptor_group = 0;
8828 g_b_init_is_valid_sid = 0;
8829 g_b_init_create_toolhelp32_snapshot = 0;
8830 g_b_init_process32_first = 0;
8831 g_b_init_process32_next = 0;
8832 g_b_init_open_thread_token = 0;
8833 g_b_init_impersonate_self = 0;
8834 g_b_init_revert_to_self = 0;
8835 g_b_init_get_process_memory_info = 0;
8836 g_b_init_get_process_working_set_size = 0;
8837 g_b_init_global_memory_status = 0;
8838 g_b_init_global_memory_status_ex = 0;
8839 g_b_init_equal_sid = 0;
8840 g_b_init_copy_sid = 0;
8841 g_b_init_get_length_sid = 0;
8842 g_b_init_get_native_system_info = 0;
8843 g_b_init_get_system_times = 0;
8844 g_b_init_create_symbolic_link_w = 0;
8845 g_b_init_create_symbolic_link_a = 0;
8846 g_b_init_get_security_descriptor_dacl = 0;
8847 g_b_init_convert_sd_to_sddl = 0;
8848 g_b_init_convert_sddl_to_sd = 0;
8849 g_b_init_is_valid_security_descriptor = 0;
8850 g_b_init_set_file_security_w = 0;
8851 g_b_init_set_file_security_a = 0;
8852 g_b_init_get_adapters_info = 0;
8853 num_of_processors = 0;
8854 /* The following sets a handler for shutdown notifications for
8855 console apps. This actually applies to Emacs in both console and
8856 GUI modes, since we had to fool windows into thinking emacs is a
8857 console application to get console mode to work. */
8858 SetConsoleCtrlHandler (shutdown_handler, TRUE);
8860 /* "None" is the default group name on standalone workstations. */
8861 strcpy (dflt_group_name, "None");
8863 /* Reset, in case it has some value inherited from dump time. */
8864 w32_stat_get_owner_group = 0;
8866 /* If w32_unicode_filenames is non-zero, we will be using Unicode
8867 (a.k.a. "wide") APIs to invoke functions that accept file
8868 names. */
8869 if (is_windows_9x ())
8870 w32_unicode_filenames = 0;
8871 else
8872 w32_unicode_filenames = 1;
8875 /* For make-serial-process */
8877 serial_open (Lisp_Object port_obj)
8879 char *port = SSDATA (port_obj);
8880 HANDLE hnd;
8881 child_process *cp;
8882 int fd = -1;
8884 hnd = CreateFile (port, GENERIC_READ | GENERIC_WRITE, 0, 0,
8885 OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
8886 if (hnd == INVALID_HANDLE_VALUE)
8887 error ("Could not open %s", port);
8888 fd = (int) _open_osfhandle ((intptr_t) hnd, 0);
8889 if (fd == -1)
8890 error ("Could not open %s", port);
8892 cp = new_child ();
8893 if (!cp)
8894 error ("Could not create child process");
8895 cp->fd = fd;
8896 cp->status = STATUS_READ_ACKNOWLEDGED;
8897 fd_info[ fd ].hnd = hnd;
8898 fd_info[ fd ].flags |=
8899 FILE_READ | FILE_WRITE | FILE_BINARY | FILE_SERIAL;
8900 if (fd_info[ fd ].cp != NULL)
8902 error ("fd_info[fd = %d] is already in use", fd);
8904 fd_info[ fd ].cp = cp;
8905 cp->ovl_read.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
8906 if (cp->ovl_read.hEvent == NULL)
8907 error ("Could not create read event");
8908 cp->ovl_write.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
8909 if (cp->ovl_write.hEvent == NULL)
8910 error ("Could not create write event");
8912 return fd;
8915 /* For serial-process-configure */
8916 void
8917 serial_configure (struct Lisp_Process *p, Lisp_Object contact)
8919 Lisp_Object childp2 = Qnil;
8920 Lisp_Object tem = Qnil;
8921 HANDLE hnd;
8922 DCB dcb;
8923 COMMTIMEOUTS ct;
8924 char summary[4] = "???"; /* This usually becomes "8N1". */
8926 if ((fd_info[ p->outfd ].flags & FILE_SERIAL) == 0)
8927 error ("Not a serial process");
8928 hnd = fd_info[ p->outfd ].hnd;
8930 childp2 = Fcopy_sequence (p->childp);
8932 /* Initialize timeouts for blocking read and blocking write. */
8933 if (!GetCommTimeouts (hnd, &ct))
8934 error ("GetCommTimeouts() failed");
8935 ct.ReadIntervalTimeout = 0;
8936 ct.ReadTotalTimeoutMultiplier = 0;
8937 ct.ReadTotalTimeoutConstant = 0;
8938 ct.WriteTotalTimeoutMultiplier = 0;
8939 ct.WriteTotalTimeoutConstant = 0;
8940 if (!SetCommTimeouts (hnd, &ct))
8941 error ("SetCommTimeouts() failed");
8942 /* Read port attributes and prepare default configuration. */
8943 memset (&dcb, 0, sizeof (dcb));
8944 dcb.DCBlength = sizeof (DCB);
8945 if (!GetCommState (hnd, &dcb))
8946 error ("GetCommState() failed");
8947 dcb.fBinary = TRUE;
8948 dcb.fNull = FALSE;
8949 dcb.fAbortOnError = FALSE;
8950 /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
8951 dcb.ErrorChar = 0;
8952 dcb.EofChar = 0;
8953 dcb.EvtChar = 0;
8955 /* Configure speed. */
8956 if (!NILP (Fplist_member (contact, QCspeed)))
8957 tem = Fplist_get (contact, QCspeed);
8958 else
8959 tem = Fplist_get (p->childp, QCspeed);
8960 CHECK_NUMBER (tem);
8961 dcb.BaudRate = XINT (tem);
8962 childp2 = Fplist_put (childp2, QCspeed, tem);
8964 /* Configure bytesize. */
8965 if (!NILP (Fplist_member (contact, QCbytesize)))
8966 tem = Fplist_get (contact, QCbytesize);
8967 else
8968 tem = Fplist_get (p->childp, QCbytesize);
8969 if (NILP (tem))
8970 tem = make_number (8);
8971 CHECK_NUMBER (tem);
8972 if (XINT (tem) != 7 && XINT (tem) != 8)
8973 error (":bytesize must be nil (8), 7, or 8");
8974 dcb.ByteSize = XINT (tem);
8975 summary[0] = XINT (tem) + '0';
8976 childp2 = Fplist_put (childp2, QCbytesize, tem);
8978 /* Configure parity. */
8979 if (!NILP (Fplist_member (contact, QCparity)))
8980 tem = Fplist_get (contact, QCparity);
8981 else
8982 tem = Fplist_get (p->childp, QCparity);
8983 if (!NILP (tem) && !EQ (tem, Qeven) && !EQ (tem, Qodd))
8984 error (":parity must be nil (no parity), `even', or `odd'");
8985 dcb.fParity = FALSE;
8986 dcb.Parity = NOPARITY;
8987 dcb.fErrorChar = FALSE;
8988 if (NILP (tem))
8990 summary[1] = 'N';
8992 else if (EQ (tem, Qeven))
8994 summary[1] = 'E';
8995 dcb.fParity = TRUE;
8996 dcb.Parity = EVENPARITY;
8997 dcb.fErrorChar = TRUE;
8999 else if (EQ (tem, Qodd))
9001 summary[1] = 'O';
9002 dcb.fParity = TRUE;
9003 dcb.Parity = ODDPARITY;
9004 dcb.fErrorChar = TRUE;
9006 childp2 = Fplist_put (childp2, QCparity, tem);
9008 /* Configure stopbits. */
9009 if (!NILP (Fplist_member (contact, QCstopbits)))
9010 tem = Fplist_get (contact, QCstopbits);
9011 else
9012 tem = Fplist_get (p->childp, QCstopbits);
9013 if (NILP (tem))
9014 tem = make_number (1);
9015 CHECK_NUMBER (tem);
9016 if (XINT (tem) != 1 && XINT (tem) != 2)
9017 error (":stopbits must be nil (1 stopbit), 1, or 2");
9018 summary[2] = XINT (tem) + '0';
9019 if (XINT (tem) == 1)
9020 dcb.StopBits = ONESTOPBIT;
9021 else if (XINT (tem) == 2)
9022 dcb.StopBits = TWOSTOPBITS;
9023 childp2 = Fplist_put (childp2, QCstopbits, tem);
9025 /* Configure flowcontrol. */
9026 if (!NILP (Fplist_member (contact, QCflowcontrol)))
9027 tem = Fplist_get (contact, QCflowcontrol);
9028 else
9029 tem = Fplist_get (p->childp, QCflowcontrol);
9030 if (!NILP (tem) && !EQ (tem, Qhw) && !EQ (tem, Qsw))
9031 error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
9032 dcb.fOutxCtsFlow = FALSE;
9033 dcb.fOutxDsrFlow = FALSE;
9034 dcb.fDtrControl = DTR_CONTROL_DISABLE;
9035 dcb.fDsrSensitivity = FALSE;
9036 dcb.fTXContinueOnXoff = FALSE;
9037 dcb.fOutX = FALSE;
9038 dcb.fInX = FALSE;
9039 dcb.fRtsControl = RTS_CONTROL_DISABLE;
9040 dcb.XonChar = 17; /* Control-Q */
9041 dcb.XoffChar = 19; /* Control-S */
9042 if (NILP (tem))
9044 /* Already configured. */
9046 else if (EQ (tem, Qhw))
9048 dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
9049 dcb.fOutxCtsFlow = TRUE;
9051 else if (EQ (tem, Qsw))
9053 dcb.fOutX = TRUE;
9054 dcb.fInX = TRUE;
9056 childp2 = Fplist_put (childp2, QCflowcontrol, tem);
9058 /* Activate configuration. */
9059 if (!SetCommState (hnd, &dcb))
9060 error ("SetCommState() failed");
9062 childp2 = Fplist_put (childp2, QCsummary, build_string (summary));
9063 pset_childp (p, childp2);
9066 #ifdef HAVE_GNUTLS
9068 ssize_t
9069 emacs_gnutls_pull (gnutls_transport_ptr_t p, void* buf, size_t sz)
9071 int n, err;
9072 SELECT_TYPE fdset;
9073 struct timespec timeout;
9074 struct Lisp_Process *process = (struct Lisp_Process *)p;
9075 int fd = process->infd;
9077 n = sys_read (fd, (char*)buf, sz);
9079 if (n >= 0)
9080 return n;
9082 err = errno;
9084 /* Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
9085 if (err == EWOULDBLOCK)
9086 err = EAGAIN;
9088 emacs_gnutls_transport_set_errno (process->gnutls_state, err);
9090 return -1;
9093 ssize_t
9094 emacs_gnutls_push (gnutls_transport_ptr_t p, const void* buf, size_t sz)
9096 struct Lisp_Process *process = (struct Lisp_Process *)p;
9097 int fd = process->outfd;
9098 ssize_t n = sys_write (fd, buf, sz);
9100 /* 0 or more bytes written means everything went fine. */
9101 if (n >= 0)
9102 return n;
9104 /* Negative bytes written means we got an error in errno.
9105 Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
9106 emacs_gnutls_transport_set_errno (process->gnutls_state,
9107 errno == EWOULDBLOCK ? EAGAIN : errno);
9109 return -1;
9111 #endif /* HAVE_GNUTLS */
9113 /* end of w32.c */