]> code.delx.au - gnu-emacs/blob - src/w32.c
Merge from origin/emacs-24
[gnu-emacs] / src / w32.c
1 /* Utility and Unix shadow routines for GNU Emacs on the Microsoft Windows API.
2
3 Copyright (C) 1994-1995, 2000-2015 Free Software Foundation, Inc.
4
5 This file is part of GNU Emacs.
6
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.
11
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.
16
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/>. */
19
20 /*
21 Geoff Voelker (voelker@cs.washington.edu) 7-29-94
22 */
23
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>
39
40 /* must include CRT headers *before* config.h */
41
42 #include <config.h>
43 #include <mbstring.h> /* for _mbspbrk, _mbslwr, _mbsrchr, ... */
44
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
57
58 #undef close
59 #undef dup
60 #undef dup2
61 #undef pipe
62 #undef read
63 #undef write
64
65 #undef strerror
66
67 #undef localtime
68
69 #include "lisp.h"
70 #include "epaths.h" /* for SHELL */
71
72 #include <pwd.h>
73 #include <grp.h>
74
75 /* MinGW64 defines these in its _mingw.h. */
76 #ifndef _ANONYMOUS_UNION
77 # define _ANONYMOUS_UNION
78 #endif
79 #ifndef _ANONYMOUS_STRUCT
80 # define _ANONYMOUS_STRUCT
81 #endif
82 #include <windows.h>
83 /* Some versions of compiler define MEMORYSTATUSEX, some don't, so we
84 use a different name to avoid compilation problems. */
85 typedef struct _MEMORY_STATUS_EX {
86 DWORD dwLength;
87 DWORD dwMemoryLoad;
88 DWORDLONG ullTotalPhys;
89 DWORDLONG ullAvailPhys;
90 DWORDLONG ullTotalPageFile;
91 DWORDLONG ullAvailPageFile;
92 DWORDLONG ullTotalVirtual;
93 DWORDLONG ullAvailVirtual;
94 DWORDLONG ullAvailExtendedVirtual;
95 } MEMORY_STATUS_EX,*LPMEMORY_STATUS_EX;
96
97 /* These are here so that GDB would know about these data types. This
98 allows to attach GDB to Emacs when a fatal exception is triggered
99 and Windows pops up the "application needs to be closed" dialog.
100 At that point, _gnu_exception_handler, the top-level exception
101 handler installed by the MinGW startup code, is somewhere on the
102 call-stack of the main thread, so going to that call frame and
103 looking at the argument to _gnu_exception_handler, which is a
104 PEXCEPTION_POINTERS pointer, can reveal the exception code
105 (excptr->ExceptionRecord->ExceptionCode) and the address where the
106 exception happened (excptr->ExceptionRecord->ExceptionAddress), as
107 well as some additional information specific to the exception. */
108 PEXCEPTION_POINTERS excptr;
109 PEXCEPTION_RECORD excprec;
110 PCONTEXT ctxrec;
111
112 #include <lmcons.h>
113 #include <shlobj.h>
114
115 #include <tlhelp32.h>
116 #include <psapi.h>
117 #ifndef _MSC_VER
118 #include <w32api.h>
119 #endif
120 #if _WIN32_WINNT < 0x0500
121 #if !defined (__MINGW32__) || __W32API_MAJOR_VERSION < 3 || (__W32API_MAJOR_VERSION == 3 && __W32API_MINOR_VERSION < 15)
122 /* This either is not in psapi.h or guarded by higher value of
123 _WIN32_WINNT than what we use. w32api supplied with MinGW 3.15
124 defines it in psapi.h */
125 typedef struct _PROCESS_MEMORY_COUNTERS_EX {
126 DWORD cb;
127 DWORD PageFaultCount;
128 SIZE_T PeakWorkingSetSize;
129 SIZE_T WorkingSetSize;
130 SIZE_T QuotaPeakPagedPoolUsage;
131 SIZE_T QuotaPagedPoolUsage;
132 SIZE_T QuotaPeakNonPagedPoolUsage;
133 SIZE_T QuotaNonPagedPoolUsage;
134 SIZE_T PagefileUsage;
135 SIZE_T PeakPagefileUsage;
136 SIZE_T PrivateUsage;
137 } PROCESS_MEMORY_COUNTERS_EX,*PPROCESS_MEMORY_COUNTERS_EX;
138 #endif
139 #endif
140
141 #include <winioctl.h>
142 #include <aclapi.h>
143 #include <sddl.h>
144
145 #include <sys/acl.h>
146 #include <acl.h>
147
148 /* This is not in MinGW's sddl.h (but they are in MSVC headers), so we
149 define them by hand if not already defined. */
150 #ifndef SDDL_REVISION_1
151 #define SDDL_REVISION_1 1
152 #endif /* SDDL_REVISION_1 */
153
154 #if defined(_MSC_VER) || defined(MINGW_W64)
155 /* MSVC and MinGW64 don't provide the definition of
156 REPARSE_DATA_BUFFER and the associated macros, except on ntifs.h,
157 which cannot be included because it triggers conflicts with other
158 Windows API headers. So we define it here by hand. */
159
160 typedef struct _REPARSE_DATA_BUFFER {
161 ULONG ReparseTag;
162 USHORT ReparseDataLength;
163 USHORT Reserved;
164 union {
165 struct {
166 USHORT SubstituteNameOffset;
167 USHORT SubstituteNameLength;
168 USHORT PrintNameOffset;
169 USHORT PrintNameLength;
170 ULONG Flags;
171 WCHAR PathBuffer[1];
172 } SymbolicLinkReparseBuffer;
173 struct {
174 USHORT SubstituteNameOffset;
175 USHORT SubstituteNameLength;
176 USHORT PrintNameOffset;
177 USHORT PrintNameLength;
178 WCHAR PathBuffer[1];
179 } MountPointReparseBuffer;
180 struct {
181 UCHAR DataBuffer[1];
182 } GenericReparseBuffer;
183 } DUMMYUNIONNAME;
184 } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
185
186 #ifndef FILE_DEVICE_FILE_SYSTEM
187 #define FILE_DEVICE_FILE_SYSTEM 9
188 #endif
189 #ifndef METHOD_BUFFERED
190 #define METHOD_BUFFERED 0
191 #endif
192 #ifndef FILE_ANY_ACCESS
193 #define FILE_ANY_ACCESS 0x00000000
194 #endif
195 #ifndef CTL_CODE
196 #define CTL_CODE(t,f,m,a) (((t)<<16)|((a)<<14)|((f)<<2)|(m))
197 #endif
198 /* MinGW64 defines FSCTL_GET_REPARSE_POINT on winioctl.h. */
199 #ifndef FSCTL_GET_REPARSE_POINT
200 #define FSCTL_GET_REPARSE_POINT \
201 CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS)
202 #endif
203 #endif
204
205 /* TCP connection support. */
206 #include <sys/socket.h>
207 #undef socket
208 #undef bind
209 #undef connect
210 #undef htons
211 #undef ntohs
212 #undef inet_addr
213 #undef gethostname
214 #undef gethostbyname
215 #undef getservbyname
216 #undef getpeername
217 #undef shutdown
218 #undef setsockopt
219 #undef listen
220 #undef getsockname
221 #undef accept
222 #undef recvfrom
223 #undef sendto
224
225 #include <iphlpapi.h> /* should be after winsock2.h */
226
227 #include "w32.h"
228 #include <dirent.h>
229 #include "w32common.h"
230 #include "w32heap.h"
231 #include "w32select.h"
232 #include "systime.h"
233 #include "dispextern.h" /* for xstrcasecmp */
234 #include "coding.h" /* for Vlocale_coding_system */
235
236 #include "careadlinkat.h"
237 #include "allocator.h"
238
239 /* For serial_configure and serial_open. */
240 #include "process.h"
241
242 typedef HRESULT (WINAPI * ShGetFolderPath_fn)
243 (IN HWND, IN int, IN HANDLE, IN DWORD, OUT char *);
244
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);
252
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);
258
259
260
261 \f
262 /* Initialization states.
263
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_set_named_security_info_w;
307 static BOOL g_b_init_set_named_security_info_a;
308 static BOOL g_b_init_get_adapters_info;
309
310 BOOL g_b_init_compare_string_w;
311
312 /*
313 BEGIN: Wrapper functions around OpenProcessToken
314 and other functions in advapi32.dll that are only
315 supported in Windows NT / 2k / XP
316 */
317 /* ** Function pointer typedefs ** */
318 typedef BOOL (WINAPI * OpenProcessToken_Proc) (
319 HANDLE ProcessHandle,
320 DWORD DesiredAccess,
321 PHANDLE TokenHandle);
322 typedef BOOL (WINAPI * GetTokenInformation_Proc) (
323 HANDLE TokenHandle,
324 TOKEN_INFORMATION_CLASS TokenInformationClass,
325 LPVOID TokenInformation,
326 DWORD TokenInformationLength,
327 PDWORD ReturnLength);
328 typedef BOOL (WINAPI * GetProcessTimes_Proc) (
329 HANDLE process_handle,
330 LPFILETIME creation_time,
331 LPFILETIME exit_time,
332 LPFILETIME kernel_time,
333 LPFILETIME user_time);
334
335 GetProcessTimes_Proc get_process_times_fn = NULL;
336
337 #ifdef _UNICODE
338 const char * const LookupAccountSid_Name = "LookupAccountSidW";
339 #else
340 const char * const LookupAccountSid_Name = "LookupAccountSidA";
341 #endif
342 typedef BOOL (WINAPI * LookupAccountSid_Proc) (
343 LPCTSTR lpSystemName,
344 PSID Sid,
345 LPTSTR Name,
346 LPDWORD cbName,
347 LPTSTR DomainName,
348 LPDWORD cbDomainName,
349 PSID_NAME_USE peUse);
350 typedef PDWORD (WINAPI * GetSidSubAuthority_Proc) (
351 PSID pSid,
352 DWORD n);
353 typedef PUCHAR (WINAPI * GetSidSubAuthorityCount_Proc) (
354 PSID pSid);
355 typedef DWORD (WINAPI * GetSecurityInfo_Proc) (
356 HANDLE handle,
357 SE_OBJECT_TYPE ObjectType,
358 SECURITY_INFORMATION SecurityInfo,
359 PSID *ppsidOwner,
360 PSID *ppsidGroup,
361 PACL *ppDacl,
362 PACL *ppSacl,
363 PSECURITY_DESCRIPTOR *ppSecurityDescriptor);
364 typedef BOOL (WINAPI * GetFileSecurityW_Proc) (
365 LPCWSTR lpFileName,
366 SECURITY_INFORMATION RequestedInformation,
367 PSECURITY_DESCRIPTOR pSecurityDescriptor,
368 DWORD nLength,
369 LPDWORD lpnLengthNeeded);
370 typedef BOOL (WINAPI * GetFileSecurityA_Proc) (
371 LPCSTR lpFileName,
372 SECURITY_INFORMATION RequestedInformation,
373 PSECURITY_DESCRIPTOR pSecurityDescriptor,
374 DWORD nLength,
375 LPDWORD lpnLengthNeeded);
376 typedef BOOL (WINAPI *SetFileSecurityW_Proc) (
377 LPCWSTR lpFileName,
378 SECURITY_INFORMATION SecurityInformation,
379 PSECURITY_DESCRIPTOR pSecurityDescriptor);
380 typedef BOOL (WINAPI *SetFileSecurityA_Proc) (
381 LPCSTR lpFileName,
382 SECURITY_INFORMATION SecurityInformation,
383 PSECURITY_DESCRIPTOR pSecurityDescriptor);
384 typedef DWORD (WINAPI *SetNamedSecurityInfoW_Proc) (
385 LPCWSTR lpObjectName,
386 SE_OBJECT_TYPE ObjectType,
387 SECURITY_INFORMATION SecurityInformation,
388 PSID psidOwner,
389 PSID psidGroup,
390 PACL pDacl,
391 PACL pSacl);
392 typedef DWORD (WINAPI *SetNamedSecurityInfoA_Proc) (
393 LPCSTR lpObjectName,
394 SE_OBJECT_TYPE ObjectType,
395 SECURITY_INFORMATION SecurityInformation,
396 PSID psidOwner,
397 PSID psidGroup,
398 PACL pDacl,
399 PACL pSacl);
400 typedef BOOL (WINAPI * GetSecurityDescriptorOwner_Proc) (
401 PSECURITY_DESCRIPTOR pSecurityDescriptor,
402 PSID *pOwner,
403 LPBOOL lpbOwnerDefaulted);
404 typedef BOOL (WINAPI * GetSecurityDescriptorGroup_Proc) (
405 PSECURITY_DESCRIPTOR pSecurityDescriptor,
406 PSID *pGroup,
407 LPBOOL lpbGroupDefaulted);
408 typedef BOOL (WINAPI *GetSecurityDescriptorDacl_Proc) (
409 PSECURITY_DESCRIPTOR pSecurityDescriptor,
410 LPBOOL lpbDaclPresent,
411 PACL *pDacl,
412 LPBOOL lpbDaclDefaulted);
413 typedef BOOL (WINAPI * IsValidSid_Proc) (
414 PSID sid);
415 typedef HANDLE (WINAPI * CreateToolhelp32Snapshot_Proc) (
416 DWORD dwFlags,
417 DWORD th32ProcessID);
418 typedef BOOL (WINAPI * Process32First_Proc) (
419 HANDLE hSnapshot,
420 LPPROCESSENTRY32 lppe);
421 typedef BOOL (WINAPI * Process32Next_Proc) (
422 HANDLE hSnapshot,
423 LPPROCESSENTRY32 lppe);
424 typedef BOOL (WINAPI * OpenThreadToken_Proc) (
425 HANDLE ThreadHandle,
426 DWORD DesiredAccess,
427 BOOL OpenAsSelf,
428 PHANDLE TokenHandle);
429 typedef BOOL (WINAPI * ImpersonateSelf_Proc) (
430 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel);
431 typedef BOOL (WINAPI * RevertToSelf_Proc) (void);
432 typedef BOOL (WINAPI * GetProcessMemoryInfo_Proc) (
433 HANDLE Process,
434 PPROCESS_MEMORY_COUNTERS ppsmemCounters,
435 DWORD cb);
436 typedef BOOL (WINAPI * GetProcessWorkingSetSize_Proc) (
437 HANDLE hProcess,
438 PSIZE_T lpMinimumWorkingSetSize,
439 PSIZE_T lpMaximumWorkingSetSize);
440 typedef BOOL (WINAPI * GlobalMemoryStatus_Proc) (
441 LPMEMORYSTATUS lpBuffer);
442 typedef BOOL (WINAPI * GlobalMemoryStatusEx_Proc) (
443 LPMEMORY_STATUS_EX lpBuffer);
444 typedef BOOL (WINAPI * CopySid_Proc) (
445 DWORD nDestinationSidLength,
446 PSID pDestinationSid,
447 PSID pSourceSid);
448 typedef BOOL (WINAPI * EqualSid_Proc) (
449 PSID pSid1,
450 PSID pSid2);
451 typedef DWORD (WINAPI * GetLengthSid_Proc) (
452 PSID pSid);
453 typedef void (WINAPI * GetNativeSystemInfo_Proc) (
454 LPSYSTEM_INFO lpSystemInfo);
455 typedef BOOL (WINAPI * GetSystemTimes_Proc) (
456 LPFILETIME lpIdleTime,
457 LPFILETIME lpKernelTime,
458 LPFILETIME lpUserTime);
459 typedef BOOLEAN (WINAPI *CreateSymbolicLinkW_Proc) (
460 LPCWSTR lpSymlinkFileName,
461 LPCWSTR lpTargetFileName,
462 DWORD dwFlags);
463 typedef BOOLEAN (WINAPI *CreateSymbolicLinkA_Proc) (
464 LPCSTR lpSymlinkFileName,
465 LPCSTR lpTargetFileName,
466 DWORD dwFlags);
467 typedef BOOL (WINAPI *ConvertStringSecurityDescriptorToSecurityDescriptor_Proc) (
468 LPCTSTR StringSecurityDescriptor,
469 DWORD StringSDRevision,
470 PSECURITY_DESCRIPTOR *SecurityDescriptor,
471 PULONG SecurityDescriptorSize);
472 typedef BOOL (WINAPI *ConvertSecurityDescriptorToStringSecurityDescriptor_Proc) (
473 PSECURITY_DESCRIPTOR SecurityDescriptor,
474 DWORD RequestedStringSDRevision,
475 SECURITY_INFORMATION SecurityInformation,
476 LPTSTR *StringSecurityDescriptor,
477 PULONG StringSecurityDescriptorLen);
478 typedef BOOL (WINAPI *IsValidSecurityDescriptor_Proc) (PSECURITY_DESCRIPTOR);
479 typedef DWORD (WINAPI *GetAdaptersInfo_Proc) (
480 PIP_ADAPTER_INFO pAdapterInfo,
481 PULONG pOutBufLen);
482
483 int (WINAPI *pMultiByteToWideChar)(UINT,DWORD,LPCSTR,int,LPWSTR,int);
484 int (WINAPI *pWideCharToMultiByte)(UINT,DWORD,LPCWSTR,int,LPSTR,int,LPCSTR,LPBOOL);
485
486 /* ** A utility function ** */
487 static BOOL
488 is_windows_9x (void)
489 {
490 static BOOL s_b_ret = 0;
491 OSVERSIONINFO os_ver;
492 if (g_b_init_is_windows_9x == 0)
493 {
494 g_b_init_is_windows_9x = 1;
495 ZeroMemory (&os_ver, sizeof (OSVERSIONINFO));
496 os_ver.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
497 if (GetVersionEx (&os_ver))
498 {
499 s_b_ret = (os_ver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
500 }
501 }
502 return s_b_ret;
503 }
504
505 static Lisp_Object ltime (ULONGLONG);
506
507 /* Get total user and system times for get-internal-run-time.
508 Returns a list of integers if the times are provided by the OS
509 (NT derivatives), otherwise it returns the result of current-time. */
510 Lisp_Object
511 w32_get_internal_run_time (void)
512 {
513 if (get_process_times_fn)
514 {
515 FILETIME create, exit, kernel, user;
516 HANDLE proc = GetCurrentProcess ();
517 if ((*get_process_times_fn) (proc, &create, &exit, &kernel, &user))
518 {
519 LARGE_INTEGER user_int, kernel_int, total;
520 user_int.LowPart = user.dwLowDateTime;
521 user_int.HighPart = user.dwHighDateTime;
522 kernel_int.LowPart = kernel.dwLowDateTime;
523 kernel_int.HighPart = kernel.dwHighDateTime;
524 total.QuadPart = user_int.QuadPart + kernel_int.QuadPart;
525 return ltime (total.QuadPart);
526 }
527 }
528
529 return Fcurrent_time ();
530 }
531
532 /* ** The wrapper functions ** */
533
534 static BOOL WINAPI
535 open_process_token (HANDLE ProcessHandle,
536 DWORD DesiredAccess,
537 PHANDLE TokenHandle)
538 {
539 static OpenProcessToken_Proc s_pfn_Open_Process_Token = NULL;
540 HMODULE hm_advapi32 = NULL;
541 if (is_windows_9x () == TRUE)
542 {
543 return FALSE;
544 }
545 if (g_b_init_open_process_token == 0)
546 {
547 g_b_init_open_process_token = 1;
548 hm_advapi32 = LoadLibrary ("Advapi32.dll");
549 s_pfn_Open_Process_Token =
550 (OpenProcessToken_Proc) GetProcAddress (hm_advapi32, "OpenProcessToken");
551 }
552 if (s_pfn_Open_Process_Token == NULL)
553 {
554 return FALSE;
555 }
556 return (
557 s_pfn_Open_Process_Token (
558 ProcessHandle,
559 DesiredAccess,
560 TokenHandle)
561 );
562 }
563
564 static BOOL WINAPI
565 get_token_information (HANDLE TokenHandle,
566 TOKEN_INFORMATION_CLASS TokenInformationClass,
567 LPVOID TokenInformation,
568 DWORD TokenInformationLength,
569 PDWORD ReturnLength)
570 {
571 static GetTokenInformation_Proc s_pfn_Get_Token_Information = NULL;
572 HMODULE hm_advapi32 = NULL;
573 if (is_windows_9x () == TRUE)
574 {
575 return FALSE;
576 }
577 if (g_b_init_get_token_information == 0)
578 {
579 g_b_init_get_token_information = 1;
580 hm_advapi32 = LoadLibrary ("Advapi32.dll");
581 s_pfn_Get_Token_Information =
582 (GetTokenInformation_Proc) GetProcAddress (hm_advapi32, "GetTokenInformation");
583 }
584 if (s_pfn_Get_Token_Information == NULL)
585 {
586 return FALSE;
587 }
588 return (
589 s_pfn_Get_Token_Information (
590 TokenHandle,
591 TokenInformationClass,
592 TokenInformation,
593 TokenInformationLength,
594 ReturnLength)
595 );
596 }
597
598 static BOOL WINAPI
599 lookup_account_sid (LPCTSTR lpSystemName,
600 PSID Sid,
601 LPTSTR Name,
602 LPDWORD cbName,
603 LPTSTR DomainName,
604 LPDWORD cbDomainName,
605 PSID_NAME_USE peUse)
606 {
607 static LookupAccountSid_Proc s_pfn_Lookup_Account_Sid = NULL;
608 HMODULE hm_advapi32 = NULL;
609 if (is_windows_9x () == TRUE)
610 {
611 return FALSE;
612 }
613 if (g_b_init_lookup_account_sid == 0)
614 {
615 g_b_init_lookup_account_sid = 1;
616 hm_advapi32 = LoadLibrary ("Advapi32.dll");
617 s_pfn_Lookup_Account_Sid =
618 (LookupAccountSid_Proc) GetProcAddress (hm_advapi32, LookupAccountSid_Name);
619 }
620 if (s_pfn_Lookup_Account_Sid == NULL)
621 {
622 return FALSE;
623 }
624 return (
625 s_pfn_Lookup_Account_Sid (
626 lpSystemName,
627 Sid,
628 Name,
629 cbName,
630 DomainName,
631 cbDomainName,
632 peUse)
633 );
634 }
635
636 static PDWORD WINAPI
637 get_sid_sub_authority (PSID pSid, DWORD n)
638 {
639 static GetSidSubAuthority_Proc s_pfn_Get_Sid_Sub_Authority = NULL;
640 static DWORD zero = 0U;
641 HMODULE hm_advapi32 = NULL;
642 if (is_windows_9x () == TRUE)
643 {
644 return &zero;
645 }
646 if (g_b_init_get_sid_sub_authority == 0)
647 {
648 g_b_init_get_sid_sub_authority = 1;
649 hm_advapi32 = LoadLibrary ("Advapi32.dll");
650 s_pfn_Get_Sid_Sub_Authority =
651 (GetSidSubAuthority_Proc) GetProcAddress (
652 hm_advapi32, "GetSidSubAuthority");
653 }
654 if (s_pfn_Get_Sid_Sub_Authority == NULL)
655 {
656 return &zero;
657 }
658 return (s_pfn_Get_Sid_Sub_Authority (pSid, n));
659 }
660
661 static PUCHAR WINAPI
662 get_sid_sub_authority_count (PSID pSid)
663 {
664 static GetSidSubAuthorityCount_Proc s_pfn_Get_Sid_Sub_Authority_Count = NULL;
665 static UCHAR zero = 0U;
666 HMODULE hm_advapi32 = NULL;
667 if (is_windows_9x () == TRUE)
668 {
669 return &zero;
670 }
671 if (g_b_init_get_sid_sub_authority_count == 0)
672 {
673 g_b_init_get_sid_sub_authority_count = 1;
674 hm_advapi32 = LoadLibrary ("Advapi32.dll");
675 s_pfn_Get_Sid_Sub_Authority_Count =
676 (GetSidSubAuthorityCount_Proc) GetProcAddress (
677 hm_advapi32, "GetSidSubAuthorityCount");
678 }
679 if (s_pfn_Get_Sid_Sub_Authority_Count == NULL)
680 {
681 return &zero;
682 }
683 return (s_pfn_Get_Sid_Sub_Authority_Count (pSid));
684 }
685
686 static DWORD WINAPI
687 get_security_info (HANDLE handle,
688 SE_OBJECT_TYPE ObjectType,
689 SECURITY_INFORMATION SecurityInfo,
690 PSID *ppsidOwner,
691 PSID *ppsidGroup,
692 PACL *ppDacl,
693 PACL *ppSacl,
694 PSECURITY_DESCRIPTOR *ppSecurityDescriptor)
695 {
696 static GetSecurityInfo_Proc s_pfn_Get_Security_Info = NULL;
697 HMODULE hm_advapi32 = NULL;
698 if (is_windows_9x () == TRUE)
699 {
700 return FALSE;
701 }
702 if (g_b_init_get_security_info == 0)
703 {
704 g_b_init_get_security_info = 1;
705 hm_advapi32 = LoadLibrary ("Advapi32.dll");
706 s_pfn_Get_Security_Info =
707 (GetSecurityInfo_Proc) GetProcAddress (
708 hm_advapi32, "GetSecurityInfo");
709 }
710 if (s_pfn_Get_Security_Info == NULL)
711 {
712 return FALSE;
713 }
714 return (s_pfn_Get_Security_Info (handle, ObjectType, SecurityInfo,
715 ppsidOwner, ppsidGroup, ppDacl, ppSacl,
716 ppSecurityDescriptor));
717 }
718
719 static BOOL WINAPI
720 get_file_security (const char *lpFileName,
721 SECURITY_INFORMATION RequestedInformation,
722 PSECURITY_DESCRIPTOR pSecurityDescriptor,
723 DWORD nLength,
724 LPDWORD lpnLengthNeeded)
725 {
726 static GetFileSecurityA_Proc s_pfn_Get_File_SecurityA = NULL;
727 static GetFileSecurityW_Proc s_pfn_Get_File_SecurityW = NULL;
728 HMODULE hm_advapi32 = NULL;
729 if (is_windows_9x () == TRUE)
730 {
731 errno = ENOTSUP;
732 return FALSE;
733 }
734 if (w32_unicode_filenames)
735 {
736 wchar_t filename_w[MAX_PATH];
737
738 if (g_b_init_get_file_security_w == 0)
739 {
740 g_b_init_get_file_security_w = 1;
741 hm_advapi32 = LoadLibrary ("Advapi32.dll");
742 s_pfn_Get_File_SecurityW =
743 (GetFileSecurityW_Proc) GetProcAddress (hm_advapi32,
744 "GetFileSecurityW");
745 }
746 if (s_pfn_Get_File_SecurityW == NULL)
747 {
748 errno = ENOTSUP;
749 return FALSE;
750 }
751 filename_to_utf16 (lpFileName, filename_w);
752 return (s_pfn_Get_File_SecurityW (filename_w, RequestedInformation,
753 pSecurityDescriptor, nLength,
754 lpnLengthNeeded));
755 }
756 else
757 {
758 char filename_a[MAX_PATH];
759
760 if (g_b_init_get_file_security_a == 0)
761 {
762 g_b_init_get_file_security_a = 1;
763 hm_advapi32 = LoadLibrary ("Advapi32.dll");
764 s_pfn_Get_File_SecurityA =
765 (GetFileSecurityA_Proc) GetProcAddress (hm_advapi32,
766 "GetFileSecurityA");
767 }
768 if (s_pfn_Get_File_SecurityA == NULL)
769 {
770 errno = ENOTSUP;
771 return FALSE;
772 }
773 filename_to_ansi (lpFileName, filename_a);
774 return (s_pfn_Get_File_SecurityA (filename_a, RequestedInformation,
775 pSecurityDescriptor, nLength,
776 lpnLengthNeeded));
777 }
778 }
779
780 static BOOL WINAPI
781 set_file_security (const char *lpFileName,
782 SECURITY_INFORMATION SecurityInformation,
783 PSECURITY_DESCRIPTOR pSecurityDescriptor)
784 {
785 static SetFileSecurityW_Proc s_pfn_Set_File_SecurityW = NULL;
786 static SetFileSecurityA_Proc s_pfn_Set_File_SecurityA = NULL;
787 HMODULE hm_advapi32 = NULL;
788 if (is_windows_9x () == TRUE)
789 {
790 errno = ENOTSUP;
791 return FALSE;
792 }
793 if (w32_unicode_filenames)
794 {
795 wchar_t filename_w[MAX_PATH];
796
797 if (g_b_init_set_file_security_w == 0)
798 {
799 g_b_init_set_file_security_w = 1;
800 hm_advapi32 = LoadLibrary ("Advapi32.dll");
801 s_pfn_Set_File_SecurityW =
802 (SetFileSecurityW_Proc) GetProcAddress (hm_advapi32,
803 "SetFileSecurityW");
804 }
805 if (s_pfn_Set_File_SecurityW == NULL)
806 {
807 errno = ENOTSUP;
808 return FALSE;
809 }
810 filename_to_utf16 (lpFileName, filename_w);
811 return (s_pfn_Set_File_SecurityW (filename_w, SecurityInformation,
812 pSecurityDescriptor));
813 }
814 else
815 {
816 char filename_a[MAX_PATH];
817
818 if (g_b_init_set_file_security_a == 0)
819 {
820 g_b_init_set_file_security_a = 1;
821 hm_advapi32 = LoadLibrary ("Advapi32.dll");
822 s_pfn_Set_File_SecurityA =
823 (SetFileSecurityA_Proc) GetProcAddress (hm_advapi32,
824 "SetFileSecurityA");
825 }
826 if (s_pfn_Set_File_SecurityA == NULL)
827 {
828 errno = ENOTSUP;
829 return FALSE;
830 }
831 filename_to_ansi (lpFileName, filename_a);
832 return (s_pfn_Set_File_SecurityA (filename_a, SecurityInformation,
833 pSecurityDescriptor));
834 }
835 }
836
837 static DWORD WINAPI
838 set_named_security_info (LPCTSTR lpObjectName,
839 SE_OBJECT_TYPE ObjectType,
840 SECURITY_INFORMATION SecurityInformation,
841 PSID psidOwner,
842 PSID psidGroup,
843 PACL pDacl,
844 PACL pSacl)
845 {
846 static SetNamedSecurityInfoW_Proc s_pfn_Set_Named_Security_InfoW = NULL;
847 static SetNamedSecurityInfoA_Proc s_pfn_Set_Named_Security_InfoA = NULL;
848 HMODULE hm_advapi32 = NULL;
849 if (is_windows_9x () == TRUE)
850 {
851 errno = ENOTSUP;
852 return ENOTSUP;
853 }
854 if (w32_unicode_filenames)
855 {
856 wchar_t filename_w[MAX_PATH];
857
858 if (g_b_init_set_named_security_info_w == 0)
859 {
860 g_b_init_set_named_security_info_w = 1;
861 hm_advapi32 = LoadLibrary ("Advapi32.dll");
862 s_pfn_Set_Named_Security_InfoW =
863 (SetNamedSecurityInfoW_Proc) GetProcAddress (hm_advapi32,
864 "SetNamedSecurityInfoW");
865 }
866 if (s_pfn_Set_Named_Security_InfoW == NULL)
867 {
868 errno = ENOTSUP;
869 return ENOTSUP;
870 }
871 filename_to_utf16 (lpObjectName, filename_w);
872 return (s_pfn_Set_Named_Security_InfoW (filename_w, ObjectType,
873 SecurityInformation, psidOwner,
874 psidGroup, pDacl, pSacl));
875 }
876 else
877 {
878 char filename_a[MAX_PATH];
879
880 if (g_b_init_set_named_security_info_a == 0)
881 {
882 g_b_init_set_named_security_info_a = 1;
883 hm_advapi32 = LoadLibrary ("Advapi32.dll");
884 s_pfn_Set_Named_Security_InfoA =
885 (SetNamedSecurityInfoA_Proc) GetProcAddress (hm_advapi32,
886 "SetNamedSecurityInfoA");
887 }
888 if (s_pfn_Set_Named_Security_InfoA == NULL)
889 {
890 errno = ENOTSUP;
891 return ENOTSUP;
892 }
893 filename_to_ansi (lpObjectName, filename_a);
894 return (s_pfn_Set_Named_Security_InfoA (filename_a, ObjectType,
895 SecurityInformation, psidOwner,
896 psidGroup, pDacl, pSacl));
897 }
898 }
899
900 static BOOL WINAPI
901 get_security_descriptor_owner (PSECURITY_DESCRIPTOR pSecurityDescriptor,
902 PSID *pOwner,
903 LPBOOL lpbOwnerDefaulted)
904 {
905 static GetSecurityDescriptorOwner_Proc s_pfn_Get_Security_Descriptor_Owner = NULL;
906 HMODULE hm_advapi32 = NULL;
907 if (is_windows_9x () == TRUE)
908 {
909 errno = ENOTSUP;
910 return FALSE;
911 }
912 if (g_b_init_get_security_descriptor_owner == 0)
913 {
914 g_b_init_get_security_descriptor_owner = 1;
915 hm_advapi32 = LoadLibrary ("Advapi32.dll");
916 s_pfn_Get_Security_Descriptor_Owner =
917 (GetSecurityDescriptorOwner_Proc) GetProcAddress (
918 hm_advapi32, "GetSecurityDescriptorOwner");
919 }
920 if (s_pfn_Get_Security_Descriptor_Owner == NULL)
921 {
922 errno = ENOTSUP;
923 return FALSE;
924 }
925 return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor, pOwner,
926 lpbOwnerDefaulted));
927 }
928
929 static BOOL WINAPI
930 get_security_descriptor_group (PSECURITY_DESCRIPTOR pSecurityDescriptor,
931 PSID *pGroup,
932 LPBOOL lpbGroupDefaulted)
933 {
934 static GetSecurityDescriptorGroup_Proc s_pfn_Get_Security_Descriptor_Group = NULL;
935 HMODULE hm_advapi32 = NULL;
936 if (is_windows_9x () == TRUE)
937 {
938 errno = ENOTSUP;
939 return FALSE;
940 }
941 if (g_b_init_get_security_descriptor_group == 0)
942 {
943 g_b_init_get_security_descriptor_group = 1;
944 hm_advapi32 = LoadLibrary ("Advapi32.dll");
945 s_pfn_Get_Security_Descriptor_Group =
946 (GetSecurityDescriptorGroup_Proc) GetProcAddress (
947 hm_advapi32, "GetSecurityDescriptorGroup");
948 }
949 if (s_pfn_Get_Security_Descriptor_Group == NULL)
950 {
951 errno = ENOTSUP;
952 return FALSE;
953 }
954 return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor, pGroup,
955 lpbGroupDefaulted));
956 }
957
958 static BOOL WINAPI
959 get_security_descriptor_dacl (PSECURITY_DESCRIPTOR pSecurityDescriptor,
960 LPBOOL lpbDaclPresent,
961 PACL *pDacl,
962 LPBOOL lpbDaclDefaulted)
963 {
964 static GetSecurityDescriptorDacl_Proc s_pfn_Get_Security_Descriptor_Dacl = NULL;
965 HMODULE hm_advapi32 = NULL;
966 if (is_windows_9x () == TRUE)
967 {
968 errno = ENOTSUP;
969 return FALSE;
970 }
971 if (g_b_init_get_security_descriptor_dacl == 0)
972 {
973 g_b_init_get_security_descriptor_dacl = 1;
974 hm_advapi32 = LoadLibrary ("Advapi32.dll");
975 s_pfn_Get_Security_Descriptor_Dacl =
976 (GetSecurityDescriptorDacl_Proc) GetProcAddress (
977 hm_advapi32, "GetSecurityDescriptorDacl");
978 }
979 if (s_pfn_Get_Security_Descriptor_Dacl == NULL)
980 {
981 errno = ENOTSUP;
982 return FALSE;
983 }
984 return (s_pfn_Get_Security_Descriptor_Dacl (pSecurityDescriptor,
985 lpbDaclPresent, pDacl,
986 lpbDaclDefaulted));
987 }
988
989 static BOOL WINAPI
990 is_valid_sid (PSID sid)
991 {
992 static IsValidSid_Proc s_pfn_Is_Valid_Sid = NULL;
993 HMODULE hm_advapi32 = NULL;
994 if (is_windows_9x () == TRUE)
995 {
996 return FALSE;
997 }
998 if (g_b_init_is_valid_sid == 0)
999 {
1000 g_b_init_is_valid_sid = 1;
1001 hm_advapi32 = LoadLibrary ("Advapi32.dll");
1002 s_pfn_Is_Valid_Sid =
1003 (IsValidSid_Proc) GetProcAddress (
1004 hm_advapi32, "IsValidSid");
1005 }
1006 if (s_pfn_Is_Valid_Sid == NULL)
1007 {
1008 return FALSE;
1009 }
1010 return (s_pfn_Is_Valid_Sid (sid));
1011 }
1012
1013 static BOOL WINAPI
1014 equal_sid (PSID sid1, PSID sid2)
1015 {
1016 static EqualSid_Proc s_pfn_Equal_Sid = NULL;
1017 HMODULE hm_advapi32 = NULL;
1018 if (is_windows_9x () == TRUE)
1019 {
1020 return FALSE;
1021 }
1022 if (g_b_init_equal_sid == 0)
1023 {
1024 g_b_init_equal_sid = 1;
1025 hm_advapi32 = LoadLibrary ("Advapi32.dll");
1026 s_pfn_Equal_Sid =
1027 (EqualSid_Proc) GetProcAddress (
1028 hm_advapi32, "EqualSid");
1029 }
1030 if (s_pfn_Equal_Sid == NULL)
1031 {
1032 return FALSE;
1033 }
1034 return (s_pfn_Equal_Sid (sid1, sid2));
1035 }
1036
1037 static DWORD WINAPI
1038 get_length_sid (PSID sid)
1039 {
1040 static GetLengthSid_Proc s_pfn_Get_Length_Sid = NULL;
1041 HMODULE hm_advapi32 = NULL;
1042 if (is_windows_9x () == TRUE)
1043 {
1044 return 0;
1045 }
1046 if (g_b_init_get_length_sid == 0)
1047 {
1048 g_b_init_get_length_sid = 1;
1049 hm_advapi32 = LoadLibrary ("Advapi32.dll");
1050 s_pfn_Get_Length_Sid =
1051 (GetLengthSid_Proc) GetProcAddress (
1052 hm_advapi32, "GetLengthSid");
1053 }
1054 if (s_pfn_Get_Length_Sid == NULL)
1055 {
1056 return 0;
1057 }
1058 return (s_pfn_Get_Length_Sid (sid));
1059 }
1060
1061 static BOOL WINAPI
1062 copy_sid (DWORD destlen, PSID dest, PSID src)
1063 {
1064 static CopySid_Proc s_pfn_Copy_Sid = NULL;
1065 HMODULE hm_advapi32 = NULL;
1066 if (is_windows_9x () == TRUE)
1067 {
1068 return FALSE;
1069 }
1070 if (g_b_init_copy_sid == 0)
1071 {
1072 g_b_init_copy_sid = 1;
1073 hm_advapi32 = LoadLibrary ("Advapi32.dll");
1074 s_pfn_Copy_Sid =
1075 (CopySid_Proc) GetProcAddress (
1076 hm_advapi32, "CopySid");
1077 }
1078 if (s_pfn_Copy_Sid == NULL)
1079 {
1080 return FALSE;
1081 }
1082 return (s_pfn_Copy_Sid (destlen, dest, src));
1083 }
1084
1085 /*
1086 END: Wrapper functions around OpenProcessToken
1087 and other functions in advapi32.dll that are only
1088 supported in Windows NT / 2k / XP
1089 */
1090
1091 static void WINAPI
1092 get_native_system_info (LPSYSTEM_INFO lpSystemInfo)
1093 {
1094 static GetNativeSystemInfo_Proc s_pfn_Get_Native_System_Info = NULL;
1095 if (is_windows_9x () != TRUE)
1096 {
1097 if (g_b_init_get_native_system_info == 0)
1098 {
1099 g_b_init_get_native_system_info = 1;
1100 s_pfn_Get_Native_System_Info =
1101 (GetNativeSystemInfo_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1102 "GetNativeSystemInfo");
1103 }
1104 if (s_pfn_Get_Native_System_Info != NULL)
1105 s_pfn_Get_Native_System_Info (lpSystemInfo);
1106 }
1107 else
1108 lpSystemInfo->dwNumberOfProcessors = -1;
1109 }
1110
1111 static BOOL WINAPI
1112 get_system_times (LPFILETIME lpIdleTime,
1113 LPFILETIME lpKernelTime,
1114 LPFILETIME lpUserTime)
1115 {
1116 static GetSystemTimes_Proc s_pfn_Get_System_times = NULL;
1117 if (is_windows_9x () == TRUE)
1118 {
1119 return FALSE;
1120 }
1121 if (g_b_init_get_system_times == 0)
1122 {
1123 g_b_init_get_system_times = 1;
1124 s_pfn_Get_System_times =
1125 (GetSystemTimes_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1126 "GetSystemTimes");
1127 }
1128 if (s_pfn_Get_System_times == NULL)
1129 return FALSE;
1130 return (s_pfn_Get_System_times (lpIdleTime, lpKernelTime, lpUserTime));
1131 }
1132
1133 static BOOLEAN WINAPI
1134 create_symbolic_link (LPCSTR lpSymlinkFilename,
1135 LPCSTR lpTargetFileName,
1136 DWORD dwFlags)
1137 {
1138 static CreateSymbolicLinkW_Proc s_pfn_Create_Symbolic_LinkW = NULL;
1139 static CreateSymbolicLinkA_Proc s_pfn_Create_Symbolic_LinkA = NULL;
1140 BOOLEAN retval;
1141
1142 if (is_windows_9x () == TRUE)
1143 {
1144 errno = ENOSYS;
1145 return 0;
1146 }
1147 if (w32_unicode_filenames)
1148 {
1149 wchar_t symfn_w[MAX_PATH], tgtfn_w[MAX_PATH];
1150
1151 if (g_b_init_create_symbolic_link_w == 0)
1152 {
1153 g_b_init_create_symbolic_link_w = 1;
1154 s_pfn_Create_Symbolic_LinkW =
1155 (CreateSymbolicLinkW_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1156 "CreateSymbolicLinkW");
1157 }
1158 if (s_pfn_Create_Symbolic_LinkW == NULL)
1159 {
1160 errno = ENOSYS;
1161 return 0;
1162 }
1163
1164 filename_to_utf16 (lpSymlinkFilename, symfn_w);
1165 filename_to_utf16 (lpTargetFileName, tgtfn_w);
1166 retval = s_pfn_Create_Symbolic_LinkW (symfn_w, tgtfn_w, dwFlags);
1167 /* If we were denied creation of the symlink, try again after
1168 enabling the SeCreateSymbolicLinkPrivilege for our process. */
1169 if (!retval)
1170 {
1171 TOKEN_PRIVILEGES priv_current;
1172
1173 if (enable_privilege (SE_CREATE_SYMBOLIC_LINK_NAME, TRUE,
1174 &priv_current))
1175 {
1176 retval = s_pfn_Create_Symbolic_LinkW (symfn_w, tgtfn_w, dwFlags);
1177 restore_privilege (&priv_current);
1178 revert_to_self ();
1179 }
1180 }
1181 }
1182 else
1183 {
1184 char symfn_a[MAX_PATH], tgtfn_a[MAX_PATH];
1185
1186 if (g_b_init_create_symbolic_link_a == 0)
1187 {
1188 g_b_init_create_symbolic_link_a = 1;
1189 s_pfn_Create_Symbolic_LinkA =
1190 (CreateSymbolicLinkA_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1191 "CreateSymbolicLinkA");
1192 }
1193 if (s_pfn_Create_Symbolic_LinkA == NULL)
1194 {
1195 errno = ENOSYS;
1196 return 0;
1197 }
1198
1199 filename_to_ansi (lpSymlinkFilename, symfn_a);
1200 filename_to_ansi (lpTargetFileName, tgtfn_a);
1201 retval = s_pfn_Create_Symbolic_LinkA (symfn_a, tgtfn_a, dwFlags);
1202 /* If we were denied creation of the symlink, try again after
1203 enabling the SeCreateSymbolicLinkPrivilege for our process. */
1204 if (!retval)
1205 {
1206 TOKEN_PRIVILEGES priv_current;
1207
1208 if (enable_privilege (SE_CREATE_SYMBOLIC_LINK_NAME, TRUE,
1209 &priv_current))
1210 {
1211 retval = s_pfn_Create_Symbolic_LinkA (symfn_a, tgtfn_a, dwFlags);
1212 restore_privilege (&priv_current);
1213 revert_to_self ();
1214 }
1215 }
1216 }
1217 return retval;
1218 }
1219
1220 static BOOL WINAPI
1221 is_valid_security_descriptor (PSECURITY_DESCRIPTOR pSecurityDescriptor)
1222 {
1223 static IsValidSecurityDescriptor_Proc s_pfn_Is_Valid_Security_Descriptor_Proc = NULL;
1224
1225 if (is_windows_9x () == TRUE)
1226 {
1227 errno = ENOTSUP;
1228 return FALSE;
1229 }
1230
1231 if (g_b_init_is_valid_security_descriptor == 0)
1232 {
1233 g_b_init_is_valid_security_descriptor = 1;
1234 s_pfn_Is_Valid_Security_Descriptor_Proc =
1235 (IsValidSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1236 "IsValidSecurityDescriptor");
1237 }
1238 if (s_pfn_Is_Valid_Security_Descriptor_Proc == NULL)
1239 {
1240 errno = ENOTSUP;
1241 return FALSE;
1242 }
1243
1244 return s_pfn_Is_Valid_Security_Descriptor_Proc (pSecurityDescriptor);
1245 }
1246
1247 static BOOL WINAPI
1248 convert_sd_to_sddl (PSECURITY_DESCRIPTOR SecurityDescriptor,
1249 DWORD RequestedStringSDRevision,
1250 SECURITY_INFORMATION SecurityInformation,
1251 LPTSTR *StringSecurityDescriptor,
1252 PULONG StringSecurityDescriptorLen)
1253 {
1254 static ConvertSecurityDescriptorToStringSecurityDescriptor_Proc s_pfn_Convert_SD_To_SDDL = NULL;
1255 BOOL retval;
1256
1257 if (is_windows_9x () == TRUE)
1258 {
1259 errno = ENOTSUP;
1260 return FALSE;
1261 }
1262
1263 if (g_b_init_convert_sd_to_sddl == 0)
1264 {
1265 g_b_init_convert_sd_to_sddl = 1;
1266 #ifdef _UNICODE
1267 s_pfn_Convert_SD_To_SDDL =
1268 (ConvertSecurityDescriptorToStringSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1269 "ConvertSecurityDescriptorToStringSecurityDescriptorW");
1270 #else
1271 s_pfn_Convert_SD_To_SDDL =
1272 (ConvertSecurityDescriptorToStringSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1273 "ConvertSecurityDescriptorToStringSecurityDescriptorA");
1274 #endif
1275 }
1276 if (s_pfn_Convert_SD_To_SDDL == NULL)
1277 {
1278 errno = ENOTSUP;
1279 return FALSE;
1280 }
1281
1282 retval = s_pfn_Convert_SD_To_SDDL (SecurityDescriptor,
1283 RequestedStringSDRevision,
1284 SecurityInformation,
1285 StringSecurityDescriptor,
1286 StringSecurityDescriptorLen);
1287
1288 return retval;
1289 }
1290
1291 static BOOL WINAPI
1292 convert_sddl_to_sd (LPCTSTR StringSecurityDescriptor,
1293 DWORD StringSDRevision,
1294 PSECURITY_DESCRIPTOR *SecurityDescriptor,
1295 PULONG SecurityDescriptorSize)
1296 {
1297 static ConvertStringSecurityDescriptorToSecurityDescriptor_Proc s_pfn_Convert_SDDL_To_SD = NULL;
1298 BOOL retval;
1299
1300 if (is_windows_9x () == TRUE)
1301 {
1302 errno = ENOTSUP;
1303 return FALSE;
1304 }
1305
1306 if (g_b_init_convert_sddl_to_sd == 0)
1307 {
1308 g_b_init_convert_sddl_to_sd = 1;
1309 #ifdef _UNICODE
1310 s_pfn_Convert_SDDL_To_SD =
1311 (ConvertStringSecurityDescriptorToSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1312 "ConvertStringSecurityDescriptorToSecurityDescriptorW");
1313 #else
1314 s_pfn_Convert_SDDL_To_SD =
1315 (ConvertStringSecurityDescriptorToSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1316 "ConvertStringSecurityDescriptorToSecurityDescriptorA");
1317 #endif
1318 }
1319 if (s_pfn_Convert_SDDL_To_SD == NULL)
1320 {
1321 errno = ENOTSUP;
1322 return FALSE;
1323 }
1324
1325 retval = s_pfn_Convert_SDDL_To_SD (StringSecurityDescriptor,
1326 StringSDRevision,
1327 SecurityDescriptor,
1328 SecurityDescriptorSize);
1329
1330 return retval;
1331 }
1332
1333 static DWORD WINAPI
1334 get_adapters_info (PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen)
1335 {
1336 static GetAdaptersInfo_Proc s_pfn_Get_Adapters_Info = NULL;
1337 HMODULE hm_iphlpapi = NULL;
1338
1339 if (is_windows_9x () == TRUE)
1340 return ERROR_NOT_SUPPORTED;
1341
1342 if (g_b_init_get_adapters_info == 0)
1343 {
1344 g_b_init_get_adapters_info = 1;
1345 hm_iphlpapi = LoadLibrary ("Iphlpapi.dll");
1346 if (hm_iphlpapi)
1347 s_pfn_Get_Adapters_Info = (GetAdaptersInfo_Proc)
1348 GetProcAddress (hm_iphlpapi, "GetAdaptersInfo");
1349 }
1350 if (s_pfn_Get_Adapters_Info == NULL)
1351 return ERROR_NOT_SUPPORTED;
1352 return s_pfn_Get_Adapters_Info (pAdapterInfo, pOutBufLen);
1353 }
1354
1355 \f
1356
1357 /* Return 1 if P is a valid pointer to an object of size SIZE. Return
1358 0 if P is NOT a valid pointer. Return -1 if we cannot validate P.
1359
1360 This is called from alloc.c:valid_pointer_p. */
1361 int
1362 w32_valid_pointer_p (void *p, int size)
1363 {
1364 SIZE_T done;
1365 HANDLE h = OpenProcess (PROCESS_VM_READ, FALSE, GetCurrentProcessId ());
1366
1367 if (h)
1368 {
1369 unsigned char *buf = alloca (size);
1370 int retval = ReadProcessMemory (h, p, buf, size, &done);
1371
1372 CloseHandle (h);
1373 return retval;
1374 }
1375 else
1376 return -1;
1377 }
1378
1379 \f
1380
1381 /* Here's an overview of how the Windows build supports file names
1382 that cannot be encoded by the current system codepage.
1383
1384 From the POV of Lisp and layers of C code above the functions here,
1385 Emacs on Windows pretends that its file names are encoded in UTF-8;
1386 see encode_file and decode_file on coding.c. Any file name that is
1387 passed as a unibyte string to C functions defined here is assumed
1388 to be in UTF-8 encoding. Any file name returned by functions
1389 defined here must be in UTF-8 encoding, with only a few exceptions
1390 reserved for a couple of special cases. (Be sure to use
1391 MAX_UTF8_PATH for char arrays that store UTF-8 encoded file names,
1392 as they can be much longer than MAX_PATH!)
1393
1394 The UTF-8 encoded file names cannot be passed to system APIs, as
1395 Windows does not support that. Therefore, they are converted
1396 either to UTF-16 or to the ANSI codepage, depending on the value of
1397 w32-unicode-filenames, before calling any system APIs or CRT library
1398 functions. The default value of that variable is determined by the
1399 OS on which Emacs runs: nil on Windows 9X and t otherwise, but the
1400 user can change that default (although I don't see why would she
1401 want to).
1402
1403 The 4 functions defined below, filename_to_utf16, filename_to_ansi,
1404 filename_from_utf16, and filename_from_ansi, are the workhorses of
1405 these conversions. They rely on Windows native APIs
1406 MultiByteToWideChar and WideCharToMultiByte; we cannot use
1407 functions from coding.c here, because they allocate memory, which
1408 is a bad idea on the level of libc, which is what the functions
1409 here emulate. (If you worry about performance due to constant
1410 conversion back and forth from UTF-8 to UTF-16, then don't: first,
1411 it was measured to take only a few microseconds on a not-so-fast
1412 machine, and second, that's exactly what the ANSI APIs we used
1413 before did anyway, because they are just thin wrappers around the
1414 Unicode APIs.)
1415
1416 The variables file-name-coding-system and default-file-name-coding-system
1417 still exist, but are actually used only when a file name needs to
1418 be converted to the ANSI codepage. This happens all the time when
1419 w32-unicode-filenames is nil, but can also happen from time to time
1420 when it is t. Otherwise, these variables have no effect on file-name
1421 encoding when w32-unicode-filenames is t; this is similar to
1422 selection-coding-system.
1423
1424 This arrangement works very well, but it has a few gotchas and
1425 limitations:
1426
1427 . Lisp code that encodes or decodes file names manually should
1428 normally use 'utf-8' as the coding-system on Windows,
1429 disregarding file-name-coding-system. This is a somewhat
1430 unpleasant consequence, but it cannot be avoided. Fortunately,
1431 very few Lisp packages need to do that.
1432
1433 More generally, passing to library functions (e.g., fopen or
1434 opendir) file names already encoded in the ANSI codepage is
1435 explicitly *verboten*, as all those functions, as shadowed and
1436 emulated here, assume they will receive UTF-8 encoded file names.
1437
1438 For the same reasons, no CRT function or Win32 API can be called
1439 directly in Emacs sources, without either converting the file
1440 names from UTF-8 to UTF-16 or ANSI codepage, or going through
1441 some shadowing function defined here.
1442
1443 . Environment variables stored in Vprocess_environment are encoded
1444 in the ANSI codepage, so if getenv/egetenv is used for a variable
1445 whose value is a file name or a list of directories, it needs to
1446 be converted to UTF-8, before it is used as argument to functions
1447 or decoded into a Lisp string.
1448
1449 . File names passed to external libraries, like the image libraries
1450 and GnuTLS, need special handling. These libraries generally
1451 don't support UTF-16 or UTF-8 file names, so they must get file
1452 names encoded in the ANSI codepage. To facilitate using these
1453 libraries with file names that are not encodable in the ANSI
1454 codepage, use the function ansi_encode_filename, which will try
1455 to use the short 8+3 alias of a file name if that file name is
1456 not encodable in the ANSI codepage. See image.c and gnutls.c for
1457 examples of how this should be done.
1458
1459 . Running subprocesses in non-ASCII directories and with non-ASCII
1460 file arguments is limited to the current codepage (even though
1461 Emacs is perfectly capable of finding an executable program file
1462 in a directory whose name cannot be encoded in the current
1463 codepage). This is because the command-line arguments are
1464 encoded _before_ they get to the w32-specific level, and the
1465 encoding is not known in advance (it doesn't have to be the
1466 current ANSI codepage), so w32proc.c functions cannot re-encode
1467 them in UTF-16. This should be fixed, but will also require
1468 changes in cmdproxy. The current limitation is not terribly bad
1469 anyway, since very few, if any, Windows console programs that are
1470 likely to be invoked by Emacs support UTF-16 encoded command
1471 lines.
1472
1473 . For similar reasons, server.el and emacsclient are also limited
1474 to the current ANSI codepage for now.
1475
1476 . Emacs itself can only handle command-line arguments encoded in
1477 the current codepage.
1478
1479 . Turning on w32-unicode-filename on Windows 9X (if it at all
1480 works) requires UNICOWS.DLL, which is thus a requirement even in
1481 non-GUI sessions, something the we previously avoided. */
1482
1483 \f
1484
1485 /* Converting file names from UTF-8 to either UTF-16 or the ANSI
1486 codepage defined by file-name-coding-system. */
1487
1488 /* Current codepage for encoding file names. */
1489 static int file_name_codepage;
1490
1491 /* Produce a Windows ANSI codepage suitable for encoding file names.
1492 Return the information about that codepage in CP_INFO. */
1493 static int
1494 codepage_for_filenames (CPINFO *cp_info)
1495 {
1496 /* A simple cache to avoid calling GetCPInfo every time we need to
1497 encode/decode a file name. The file-name encoding is not
1498 supposed to be changed too frequently, if ever. */
1499 static Lisp_Object last_file_name_encoding;
1500 static CPINFO cp;
1501 Lisp_Object current_encoding;
1502
1503 current_encoding = Vfile_name_coding_system;
1504 if (NILP (current_encoding))
1505 current_encoding = Vdefault_file_name_coding_system;
1506
1507 if (!EQ (last_file_name_encoding, current_encoding))
1508 {
1509 /* Default to the current ANSI codepage. */
1510 file_name_codepage = w32_ansi_code_page;
1511
1512 if (NILP (current_encoding))
1513 {
1514 char *cpname = SDATA (SYMBOL_NAME (current_encoding));
1515 char *cp = NULL, *end;
1516 int cpnum;
1517
1518 if (strncmp (cpname, "cp", 2) == 0)
1519 cp = cpname + 2;
1520 else if (strncmp (cpname, "windows-", 8) == 0)
1521 cp = cpname + 8;
1522
1523 if (cp)
1524 {
1525 end = cp;
1526 cpnum = strtol (cp, &end, 10);
1527 if (cpnum && *end == '\0' && end - cp >= 2)
1528 file_name_codepage = cpnum;
1529 }
1530 }
1531
1532 if (!file_name_codepage)
1533 file_name_codepage = CP_ACP; /* CP_ACP = 0, but let's not assume that */
1534
1535 if (!GetCPInfo (file_name_codepage, &cp))
1536 {
1537 file_name_codepage = CP_ACP;
1538 if (!GetCPInfo (file_name_codepage, &cp))
1539 emacs_abort ();
1540 }
1541 }
1542 if (cp_info)
1543 *cp_info = cp;
1544
1545 return file_name_codepage;
1546 }
1547
1548 int
1549 filename_to_utf16 (const char *fn_in, wchar_t *fn_out)
1550 {
1551 int result = pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, fn_in, -1,
1552 fn_out, MAX_PATH);
1553
1554 if (!result)
1555 {
1556 DWORD err = GetLastError ();
1557
1558 switch (err)
1559 {
1560 case ERROR_INVALID_FLAGS:
1561 case ERROR_INVALID_PARAMETER:
1562 errno = EINVAL;
1563 break;
1564 case ERROR_INSUFFICIENT_BUFFER:
1565 case ERROR_NO_UNICODE_TRANSLATION:
1566 default:
1567 errno = ENOENT;
1568 break;
1569 }
1570 return -1;
1571 }
1572 return 0;
1573 }
1574
1575 int
1576 filename_from_utf16 (const wchar_t *fn_in, char *fn_out)
1577 {
1578 int result = pWideCharToMultiByte (CP_UTF8, 0, fn_in, -1,
1579 fn_out, MAX_UTF8_PATH, NULL, NULL);
1580
1581 if (!result)
1582 {
1583 DWORD err = GetLastError ();
1584
1585 switch (err)
1586 {
1587 case ERROR_INVALID_FLAGS:
1588 case ERROR_INVALID_PARAMETER:
1589 errno = EINVAL;
1590 break;
1591 case ERROR_INSUFFICIENT_BUFFER:
1592 case ERROR_NO_UNICODE_TRANSLATION:
1593 default:
1594 errno = ENOENT;
1595 break;
1596 }
1597 return -1;
1598 }
1599 return 0;
1600 }
1601
1602 int
1603 filename_to_ansi (const char *fn_in, char *fn_out)
1604 {
1605 wchar_t fn_utf16[MAX_PATH];
1606
1607 if (filename_to_utf16 (fn_in, fn_utf16) == 0)
1608 {
1609 int result;
1610 int codepage = codepage_for_filenames (NULL);
1611
1612 result = pWideCharToMultiByte (codepage, 0, fn_utf16, -1,
1613 fn_out, MAX_PATH, NULL, NULL);
1614 if (!result)
1615 {
1616 DWORD err = GetLastError ();
1617
1618 switch (err)
1619 {
1620 case ERROR_INVALID_FLAGS:
1621 case ERROR_INVALID_PARAMETER:
1622 errno = EINVAL;
1623 break;
1624 case ERROR_INSUFFICIENT_BUFFER:
1625 case ERROR_NO_UNICODE_TRANSLATION:
1626 default:
1627 errno = ENOENT;
1628 break;
1629 }
1630 return -1;
1631 }
1632 return 0;
1633 }
1634 return -1;
1635 }
1636
1637 int
1638 filename_from_ansi (const char *fn_in, char *fn_out)
1639 {
1640 wchar_t fn_utf16[MAX_PATH];
1641 int codepage = codepage_for_filenames (NULL);
1642 int result = pMultiByteToWideChar (codepage, MB_ERR_INVALID_CHARS, fn_in, -1,
1643 fn_utf16, MAX_PATH);
1644
1645 if (!result)
1646 {
1647 DWORD err = GetLastError ();
1648
1649 switch (err)
1650 {
1651 case ERROR_INVALID_FLAGS:
1652 case ERROR_INVALID_PARAMETER:
1653 errno = EINVAL;
1654 break;
1655 case ERROR_INSUFFICIENT_BUFFER:
1656 case ERROR_NO_UNICODE_TRANSLATION:
1657 default:
1658 errno = ENOENT;
1659 break;
1660 }
1661 return -1;
1662 }
1663 return filename_from_utf16 (fn_utf16, fn_out);
1664 }
1665
1666 \f
1667
1668 /* The directory where we started, in UTF-8. */
1669 static char startup_dir[MAX_UTF8_PATH];
1670
1671 /* Get the current working directory. */
1672 char *
1673 getcwd (char *dir, int dirsize)
1674 {
1675 if (!dirsize)
1676 {
1677 errno = EINVAL;
1678 return NULL;
1679 }
1680 if (dirsize <= strlen (startup_dir))
1681 {
1682 errno = ERANGE;
1683 return NULL;
1684 }
1685 #if 0
1686 if (GetCurrentDirectory (MAXPATHLEN, dir) > 0)
1687 return dir;
1688 return NULL;
1689 #else
1690 /* Emacs doesn't actually change directory itself, it stays in the
1691 same directory where it was started. */
1692 strcpy (dir, startup_dir);
1693 return dir;
1694 #endif
1695 }
1696
1697 /* Emulate getloadavg. */
1698
1699 struct load_sample {
1700 time_t sample_time;
1701 ULONGLONG idle;
1702 ULONGLONG kernel;
1703 ULONGLONG user;
1704 };
1705
1706 /* Number of processors on this machine. */
1707 static unsigned num_of_processors;
1708
1709 /* We maintain 1-sec samples for the last 16 minutes in a circular buffer. */
1710 static struct load_sample samples[16*60];
1711 static int first_idx = -1, last_idx = -1;
1712 static int max_idx = ARRAYELTS (samples);
1713
1714 static int
1715 buf_next (int from)
1716 {
1717 int next_idx = from + 1;
1718
1719 if (next_idx >= max_idx)
1720 next_idx = 0;
1721
1722 return next_idx;
1723 }
1724
1725 static int
1726 buf_prev (int from)
1727 {
1728 int prev_idx = from - 1;
1729
1730 if (prev_idx < 0)
1731 prev_idx = max_idx - 1;
1732
1733 return prev_idx;
1734 }
1735
1736 static void
1737 sample_system_load (ULONGLONG *idle, ULONGLONG *kernel, ULONGLONG *user)
1738 {
1739 SYSTEM_INFO sysinfo;
1740 FILETIME ft_idle, ft_user, ft_kernel;
1741
1742 /* Initialize the number of processors on this machine. */
1743 if (num_of_processors <= 0)
1744 {
1745 get_native_system_info (&sysinfo);
1746 num_of_processors = sysinfo.dwNumberOfProcessors;
1747 if (num_of_processors <= 0)
1748 {
1749 GetSystemInfo (&sysinfo);
1750 num_of_processors = sysinfo.dwNumberOfProcessors;
1751 }
1752 if (num_of_processors <= 0)
1753 num_of_processors = 1;
1754 }
1755
1756 /* TODO: Take into account threads that are ready to run, by
1757 sampling the "\System\Processor Queue Length" performance
1758 counter. The code below accounts only for threads that are
1759 actually running. */
1760
1761 if (get_system_times (&ft_idle, &ft_kernel, &ft_user))
1762 {
1763 ULARGE_INTEGER uidle, ukernel, uuser;
1764
1765 memcpy (&uidle, &ft_idle, sizeof (ft_idle));
1766 memcpy (&ukernel, &ft_kernel, sizeof (ft_kernel));
1767 memcpy (&uuser, &ft_user, sizeof (ft_user));
1768 *idle = uidle.QuadPart;
1769 *kernel = ukernel.QuadPart;
1770 *user = uuser.QuadPart;
1771 }
1772 else
1773 {
1774 *idle = 0;
1775 *kernel = 0;
1776 *user = 0;
1777 }
1778 }
1779
1780 /* Produce the load average for a given time interval, using the
1781 samples in the samples[] array. WHICH can be 0, 1, or 2, meaning
1782 1-minute, 5-minute, or 15-minute average, respectively. */
1783 static double
1784 getavg (int which)
1785 {
1786 double retval = -1.0;
1787 double tdiff;
1788 int idx;
1789 double span = (which == 0 ? 1.0 : (which == 1 ? 5.0 : 15.0)) * 60;
1790 time_t now = samples[last_idx].sample_time;
1791
1792 if (first_idx != last_idx)
1793 {
1794 for (idx = buf_prev (last_idx); ; idx = buf_prev (idx))
1795 {
1796 tdiff = difftime (now, samples[idx].sample_time);
1797 if (tdiff >= span - 2*DBL_EPSILON*now)
1798 {
1799 long double sys =
1800 samples[last_idx].kernel + samples[last_idx].user
1801 - (samples[idx].kernel + samples[idx].user);
1802 long double idl = samples[last_idx].idle - samples[idx].idle;
1803
1804 retval = (1.0 - idl / sys) * num_of_processors;
1805 break;
1806 }
1807 if (idx == first_idx)
1808 break;
1809 }
1810 }
1811
1812 return retval;
1813 }
1814
1815 int
1816 getloadavg (double loadavg[], int nelem)
1817 {
1818 int elem;
1819 ULONGLONG idle, kernel, user;
1820 time_t now = time (NULL);
1821
1822 /* If system time jumped back for some reason, delete all samples
1823 whose time is later than the current wall-clock time. This
1824 prevents load average figures from becoming frozen for prolonged
1825 periods of time, when system time is reset backwards. */
1826 if (last_idx >= 0)
1827 {
1828 while (difftime (now, samples[last_idx].sample_time) < -1.0)
1829 {
1830 if (last_idx == first_idx)
1831 {
1832 first_idx = last_idx = -1;
1833 break;
1834 }
1835 last_idx = buf_prev (last_idx);
1836 }
1837 }
1838
1839 /* Store another sample. We ignore samples that are less than 1 sec
1840 apart. */
1841 if (last_idx < 0
1842 || (difftime (now, samples[last_idx].sample_time)
1843 >= 1.0 - 2*DBL_EPSILON*now))
1844 {
1845 sample_system_load (&idle, &kernel, &user);
1846 last_idx = buf_next (last_idx);
1847 samples[last_idx].sample_time = now;
1848 samples[last_idx].idle = idle;
1849 samples[last_idx].kernel = kernel;
1850 samples[last_idx].user = user;
1851 /* If the buffer has more that 15 min worth of samples, discard
1852 the old ones. */
1853 if (first_idx == -1)
1854 first_idx = last_idx;
1855 while (first_idx != last_idx
1856 && (difftime (now, samples[first_idx].sample_time)
1857 >= 15.0*60 + 2*DBL_EPSILON*now))
1858 first_idx = buf_next (first_idx);
1859 }
1860
1861 for (elem = 0; elem < nelem; elem++)
1862 {
1863 double avg = getavg (elem);
1864
1865 if (avg < 0)
1866 break;
1867 loadavg[elem] = avg;
1868 }
1869
1870 return elem;
1871 }
1872
1873 /* Emulate getpwuid, getpwnam and others. */
1874
1875 #define PASSWD_FIELD_SIZE 256
1876
1877 static char dflt_passwd_name[PASSWD_FIELD_SIZE];
1878 static char dflt_passwd_passwd[PASSWD_FIELD_SIZE];
1879 static char dflt_passwd_gecos[PASSWD_FIELD_SIZE];
1880 static char dflt_passwd_dir[MAX_UTF8_PATH];
1881 static char dflt_passwd_shell[MAX_UTF8_PATH];
1882
1883 static struct passwd dflt_passwd =
1884 {
1885 dflt_passwd_name,
1886 dflt_passwd_passwd,
1887 0,
1888 0,
1889 0,
1890 dflt_passwd_gecos,
1891 dflt_passwd_dir,
1892 dflt_passwd_shell,
1893 };
1894
1895 static char dflt_group_name[GNLEN+1];
1896
1897 static struct group dflt_group =
1898 {
1899 /* When group information is not available, we return this as the
1900 group for all files. */
1901 dflt_group_name,
1902 0,
1903 };
1904
1905 unsigned
1906 getuid (void)
1907 {
1908 return dflt_passwd.pw_uid;
1909 }
1910
1911 unsigned
1912 geteuid (void)
1913 {
1914 /* I could imagine arguing for checking to see whether the user is
1915 in the Administrators group and returning a UID of 0 for that
1916 case, but I don't know how wise that would be in the long run. */
1917 return getuid ();
1918 }
1919
1920 unsigned
1921 getgid (void)
1922 {
1923 return dflt_passwd.pw_gid;
1924 }
1925
1926 unsigned
1927 getegid (void)
1928 {
1929 return getgid ();
1930 }
1931
1932 struct passwd *
1933 getpwuid (unsigned uid)
1934 {
1935 if (uid == dflt_passwd.pw_uid)
1936 return &dflt_passwd;
1937 return NULL;
1938 }
1939
1940 struct group *
1941 getgrgid (gid_t gid)
1942 {
1943 return &dflt_group;
1944 }
1945
1946 struct passwd *
1947 getpwnam (char *name)
1948 {
1949 struct passwd *pw;
1950
1951 pw = getpwuid (getuid ());
1952 if (!pw)
1953 return pw;
1954
1955 if (xstrcasecmp (name, pw->pw_name))
1956 return NULL;
1957
1958 return pw;
1959 }
1960
1961 static void
1962 init_user_info (void)
1963 {
1964 /* Find the user's real name by opening the process token and
1965 looking up the name associated with the user-sid in that token.
1966
1967 Use the relative portion of the identifier authority value from
1968 the user-sid as the user id value (same for group id using the
1969 primary group sid from the process token). */
1970
1971 char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
1972 DWORD ulength = sizeof (uname), dlength = sizeof (domain), needed;
1973 DWORD glength = sizeof (gname);
1974 HANDLE token = NULL;
1975 SID_NAME_USE user_type;
1976 unsigned char *buf = NULL;
1977 DWORD blen = 0;
1978 TOKEN_USER user_token;
1979 TOKEN_PRIMARY_GROUP group_token;
1980 BOOL result;
1981
1982 result = open_process_token (GetCurrentProcess (), TOKEN_QUERY, &token);
1983 if (result)
1984 {
1985 result = get_token_information (token, TokenUser, NULL, 0, &blen);
1986 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
1987 {
1988 buf = xmalloc (blen);
1989 result = get_token_information (token, TokenUser,
1990 (LPVOID)buf, blen, &needed);
1991 if (result)
1992 {
1993 memcpy (&user_token, buf, sizeof (user_token));
1994 result = lookup_account_sid (NULL, user_token.User.Sid,
1995 uname, &ulength,
1996 domain, &dlength, &user_type);
1997 }
1998 }
1999 else
2000 result = FALSE;
2001 }
2002 if (result)
2003 {
2004 strcpy (dflt_passwd.pw_name, uname);
2005 /* Determine a reasonable uid value. */
2006 if (xstrcasecmp ("administrator", uname) == 0)
2007 {
2008 dflt_passwd.pw_uid = 500; /* well-known Administrator uid */
2009 dflt_passwd.pw_gid = 513; /* well-known None gid */
2010 }
2011 else
2012 {
2013 /* Use the last sub-authority value of the RID, the relative
2014 portion of the SID, as user/group ID. */
2015 dflt_passwd.pw_uid = get_rid (user_token.User.Sid);
2016
2017 /* Get group id and name. */
2018 result = get_token_information (token, TokenPrimaryGroup,
2019 (LPVOID)buf, blen, &needed);
2020 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
2021 {
2022 buf = xrealloc (buf, blen = needed);
2023 result = get_token_information (token, TokenPrimaryGroup,
2024 (LPVOID)buf, blen, &needed);
2025 }
2026 if (result)
2027 {
2028 memcpy (&group_token, buf, sizeof (group_token));
2029 dflt_passwd.pw_gid = get_rid (group_token.PrimaryGroup);
2030 dlength = sizeof (domain);
2031 /* If we can get at the real Primary Group name, use that.
2032 Otherwise, the default group name was already set to
2033 "None" in globals_of_w32. */
2034 if (lookup_account_sid (NULL, group_token.PrimaryGroup,
2035 gname, &glength, NULL, &dlength,
2036 &user_type))
2037 strcpy (dflt_group_name, gname);
2038 }
2039 else
2040 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
2041 }
2042 }
2043 /* If security calls are not supported (presumably because we
2044 are running under Windows 9X), fallback to this: */
2045 else if (GetUserName (uname, &ulength))
2046 {
2047 strcpy (dflt_passwd.pw_name, uname);
2048 if (xstrcasecmp ("administrator", uname) == 0)
2049 dflt_passwd.pw_uid = 0;
2050 else
2051 dflt_passwd.pw_uid = 123;
2052 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
2053 }
2054 else
2055 {
2056 strcpy (dflt_passwd.pw_name, "unknown");
2057 dflt_passwd.pw_uid = 123;
2058 dflt_passwd.pw_gid = 123;
2059 }
2060 dflt_group.gr_gid = dflt_passwd.pw_gid;
2061
2062 /* Set dir and shell from environment variables. */
2063 if (w32_unicode_filenames)
2064 {
2065 wchar_t *home = _wgetenv (L"HOME");
2066 wchar_t *shell = _wgetenv (L"SHELL");
2067
2068 /* Ensure HOME and SHELL are defined. */
2069 if (home == NULL)
2070 emacs_abort ();
2071 if (shell == NULL)
2072 emacs_abort ();
2073 filename_from_utf16 (home, dflt_passwd.pw_dir);
2074 filename_from_utf16 (shell, dflt_passwd.pw_shell);
2075 }
2076 else
2077 {
2078 char *home = getenv ("HOME");
2079 char *shell = getenv ("SHELL");
2080
2081 if (home == NULL)
2082 emacs_abort ();
2083 if (shell == NULL)
2084 emacs_abort ();
2085 filename_from_ansi (home, dflt_passwd.pw_dir);
2086 filename_from_ansi (shell, dflt_passwd.pw_shell);
2087 }
2088
2089 xfree (buf);
2090 if (token)
2091 CloseHandle (token);
2092 }
2093
2094 int
2095 random (void)
2096 {
2097 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
2098 return ((rand () << 15) | rand ());
2099 }
2100
2101 void
2102 srandom (int seed)
2103 {
2104 srand (seed);
2105 }
2106
2107 /* Return the maximum length in bytes of a multibyte character
2108 sequence encoded in the current ANSI codepage. This is required to
2109 correctly walk the encoded file names one character at a time. */
2110 static int
2111 max_filename_mbslen (void)
2112 {
2113 CPINFO cp_info;
2114
2115 codepage_for_filenames (&cp_info);
2116 return cp_info.MaxCharSize;
2117 }
2118
2119 /* Normalize filename by converting in-place all of its path
2120 separators to the separator specified by PATH_SEP. */
2121
2122 static void
2123 normalize_filename (register char *fp, char path_sep)
2124 {
2125 char *p2;
2126
2127 /* Always lower-case drive letters a-z, even if the filesystem
2128 preserves case in filenames.
2129 This is so filenames can be compared by string comparison
2130 functions that are case-sensitive. Even case-preserving filesystems
2131 do not distinguish case in drive letters. */
2132 p2 = fp + 1;
2133
2134 if (*p2 == ':' && *fp >= 'A' && *fp <= 'Z')
2135 {
2136 *fp += 'a' - 'A';
2137 fp += 2;
2138 }
2139
2140 while (*fp)
2141 {
2142 if ((*fp == '/' || *fp == '\\') && *fp != path_sep)
2143 *fp = path_sep;
2144 fp++;
2145 }
2146 }
2147
2148 /* Destructively turn backslashes into slashes. */
2149 void
2150 dostounix_filename (register char *p)
2151 {
2152 normalize_filename (p, '/');
2153 }
2154
2155 /* Destructively turn slashes into backslashes. */
2156 void
2157 unixtodos_filename (register char *p)
2158 {
2159 normalize_filename (p, '\\');
2160 }
2161
2162 /* Remove all CR's that are followed by a LF.
2163 (From msdos.c...probably should figure out a way to share it,
2164 although this code isn't going to ever change.) */
2165 static int
2166 crlf_to_lf (register int n, register unsigned char *buf)
2167 {
2168 unsigned char *np = buf;
2169 unsigned char *startp = buf;
2170 unsigned char *endp = buf + n;
2171
2172 if (n == 0)
2173 return n;
2174 while (buf < endp - 1)
2175 {
2176 if (*buf == 0x0d)
2177 {
2178 if (*(++buf) != 0x0a)
2179 *np++ = 0x0d;
2180 }
2181 else
2182 *np++ = *buf++;
2183 }
2184 if (buf < endp)
2185 *np++ = *buf++;
2186 return np - startp;
2187 }
2188
2189 /* Parse the root part of file name, if present. Return length and
2190 optionally store pointer to char after root. */
2191 static int
2192 parse_root (const char * name, const char ** pPath)
2193 {
2194 const char * start = name;
2195
2196 if (name == NULL)
2197 return 0;
2198
2199 /* find the root name of the volume if given */
2200 if (isalpha (name[0]) && name[1] == ':')
2201 {
2202 /* skip past drive specifier */
2203 name += 2;
2204 if (IS_DIRECTORY_SEP (name[0]))
2205 name++;
2206 }
2207 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
2208 {
2209 int slashes = 2;
2210
2211 name += 2;
2212 do
2213 {
2214 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
2215 break;
2216 name++;
2217 }
2218 while ( *name );
2219 if (IS_DIRECTORY_SEP (name[0]))
2220 name++;
2221 }
2222
2223 if (pPath)
2224 *pPath = name;
2225
2226 return name - start;
2227 }
2228
2229 /* Get long base name for name; name is assumed to be absolute. */
2230 static int
2231 get_long_basename (char * name, char * buf, int size)
2232 {
2233 HANDLE dir_handle = INVALID_HANDLE_VALUE;
2234 char fname_utf8[MAX_UTF8_PATH];
2235 int len = 0;
2236 int cstatus = -1;
2237
2238 /* Must be valid filename, no wild cards or other invalid characters. */
2239 if (strpbrk (name, "*?|<>\""))
2240 return 0;
2241
2242 if (w32_unicode_filenames)
2243 {
2244 wchar_t fname_utf16[MAX_PATH];
2245 WIN32_FIND_DATAW find_data_wide;
2246
2247 filename_to_utf16 (name, fname_utf16);
2248 dir_handle = FindFirstFileW (fname_utf16, &find_data_wide);
2249 if (dir_handle != INVALID_HANDLE_VALUE)
2250 cstatus = filename_from_utf16 (find_data_wide.cFileName, fname_utf8);
2251 }
2252 else
2253 {
2254 char fname_ansi[MAX_PATH];
2255 WIN32_FIND_DATAA find_data_ansi;
2256
2257 filename_to_ansi (name, fname_ansi);
2258 /* If the ANSI name includes ? characters, it is not encodable
2259 in the ANSI codepage. In that case, we deliver the question
2260 marks to the caller; calling FindFirstFileA in this case
2261 could return some unrelated file name in the same
2262 directory. */
2263 if (_mbspbrk (fname_ansi, "?"))
2264 {
2265 /* Find the basename of fname_ansi. */
2266 char *p = strrchr (fname_ansi, '\\');
2267
2268 if (!p)
2269 p = fname_ansi;
2270 else
2271 p++;
2272 cstatus = filename_from_ansi (p, fname_utf8);
2273 }
2274 else
2275 {
2276 dir_handle = FindFirstFileA (fname_ansi, &find_data_ansi);
2277 if (dir_handle != INVALID_HANDLE_VALUE)
2278 cstatus = filename_from_ansi (find_data_ansi.cFileName, fname_utf8);
2279 }
2280 }
2281
2282 if (cstatus == 0 && (len = strlen (fname_utf8)) < size)
2283 memcpy (buf, fname_utf8, len + 1);
2284 else
2285 len = 0;
2286
2287 if (dir_handle != INVALID_HANDLE_VALUE)
2288 FindClose (dir_handle);
2289
2290 return len;
2291 }
2292
2293 /* Get long name for file, if possible (assumed to be absolute). */
2294 BOOL
2295 w32_get_long_filename (const char * name, char * buf, int size)
2296 {
2297 char * o = buf;
2298 char * p;
2299 const char * q;
2300 char full[ MAX_UTF8_PATH ];
2301 int len;
2302
2303 len = strlen (name);
2304 if (len >= MAX_UTF8_PATH)
2305 return FALSE;
2306
2307 /* Use local copy for destructive modification. */
2308 memcpy (full, name, len+1);
2309 unixtodos_filename (full);
2310
2311 /* Copy root part verbatim. */
2312 len = parse_root (full, (const char **)&p);
2313 memcpy (o, full, len);
2314 o += len;
2315 *o = '\0';
2316 size -= len;
2317
2318 while (p != NULL && *p)
2319 {
2320 q = p;
2321 p = strchr (q, '\\');
2322 if (p) *p = '\0';
2323 len = get_long_basename (full, o, size);
2324 if (len > 0)
2325 {
2326 o += len;
2327 size -= len;
2328 if (p != NULL)
2329 {
2330 *p++ = '\\';
2331 if (size < 2)
2332 return FALSE;
2333 *o++ = '\\';
2334 size--;
2335 *o = '\0';
2336 }
2337 }
2338 else
2339 return FALSE;
2340 }
2341
2342 return TRUE;
2343 }
2344
2345 unsigned int
2346 w32_get_short_filename (const char * name, char * buf, int size)
2347 {
2348 if (w32_unicode_filenames)
2349 {
2350 wchar_t name_utf16[MAX_PATH], short_name[MAX_PATH];
2351 unsigned int retval;
2352
2353 filename_to_utf16 (name, name_utf16);
2354 retval = GetShortPathNameW (name_utf16, short_name, size);
2355 if (retval && retval < size)
2356 filename_from_utf16 (short_name, buf);
2357 return retval;
2358 }
2359 else
2360 {
2361 char name_ansi[MAX_PATH];
2362
2363 filename_to_ansi (name, name_ansi);
2364 return GetShortPathNameA (name_ansi, buf, size);
2365 }
2366 }
2367
2368 /* Re-encode FILENAME, a UTF-8 encoded unibyte string, using the
2369 MS-Windows ANSI codepage. If FILENAME includes characters not
2370 supported by the ANSI codepage, return the 8+3 alias of FILENAME,
2371 if it exists. This is needed because the w32 build wants to
2372 support file names outside of the system locale, but image
2373 libraries typically don't support wide (a.k.a. "Unicode") APIs
2374 required for that. */
2375
2376 Lisp_Object
2377 ansi_encode_filename (Lisp_Object filename)
2378 {
2379 Lisp_Object encoded_filename;
2380 char fname[MAX_PATH];
2381
2382 filename_to_ansi (SSDATA (filename), fname);
2383 if (_mbspbrk (fname, "?"))
2384 {
2385 char shortname[MAX_PATH];
2386
2387 if (w32_get_short_filename (SDATA (filename), shortname, MAX_PATH))
2388 {
2389 dostounix_filename (shortname);
2390 encoded_filename = build_string (shortname);
2391 }
2392 else
2393 encoded_filename = build_unibyte_string (fname);
2394 }
2395 else
2396 encoded_filename = build_unibyte_string (fname);
2397 return encoded_filename;
2398 }
2399
2400 static int
2401 is_unc_volume (const char *filename)
2402 {
2403 const char *ptr = filename;
2404
2405 if (!IS_DIRECTORY_SEP (ptr[0]) || !IS_DIRECTORY_SEP (ptr[1]) || !ptr[2])
2406 return 0;
2407
2408 if (strpbrk (ptr + 2, "*?|<>\"\\/"))
2409 return 0;
2410
2411 return 1;
2412 }
2413
2414 /* Emulate the Posix unsetenv. */
2415 int
2416 unsetenv (const char *name)
2417 {
2418 char *var;
2419 size_t name_len;
2420
2421 if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
2422 {
2423 errno = EINVAL;
2424 return -1;
2425 }
2426 name_len = strlen (name);
2427 /* MS docs says an environment variable cannot be longer than 32K. */
2428 if (name_len > 32767)
2429 {
2430 errno = ENOMEM;
2431 return 0;
2432 }
2433 /* It is safe to use 'alloca' with 32K size, since the stack is at
2434 least 2MB, and we set it to 8MB in the link command line. */
2435 var = alloca (name_len + 2);
2436 strncpy (var, name, name_len);
2437 var[name_len++] = '=';
2438 var[name_len] = '\0';
2439 return _putenv (var);
2440 }
2441
2442 /* MS _putenv doesn't support removing a variable when the argument
2443 does not include the '=' character, so we fix that here. */
2444 int
2445 sys_putenv (char *str)
2446 {
2447 const char *const name_end = strchr (str, '=');
2448
2449 if (name_end == NULL)
2450 {
2451 /* Remove the variable from the environment. */
2452 return unsetenv (str);
2453 }
2454
2455 return _putenv (str);
2456 }
2457
2458 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
2459
2460 LPBYTE
2461 w32_get_resource (char *key, LPDWORD lpdwtype)
2462 {
2463 LPBYTE lpvalue;
2464 HKEY hrootkey = NULL;
2465 DWORD cbData;
2466
2467 /* Check both the current user and the local machine to see if
2468 we have any resources. */
2469
2470 if (RegOpenKeyEx (HKEY_CURRENT_USER, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
2471 {
2472 lpvalue = NULL;
2473
2474 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
2475 && (lpvalue = xmalloc (cbData)) != NULL
2476 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
2477 {
2478 RegCloseKey (hrootkey);
2479 return (lpvalue);
2480 }
2481
2482 xfree (lpvalue);
2483
2484 RegCloseKey (hrootkey);
2485 }
2486
2487 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
2488 {
2489 lpvalue = NULL;
2490
2491 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
2492 && (lpvalue = xmalloc (cbData)) != NULL
2493 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
2494 {
2495 RegCloseKey (hrootkey);
2496 return (lpvalue);
2497 }
2498
2499 xfree (lpvalue);
2500
2501 RegCloseKey (hrootkey);
2502 }
2503
2504 return (NULL);
2505 }
2506
2507 /* The argv[] array holds ANSI-encoded strings, and so this function
2508 works with ANS_encoded strings. */
2509 void
2510 init_environment (char ** argv)
2511 {
2512 static const char * const tempdirs[] = {
2513 "$TMPDIR", "$TEMP", "$TMP", "c:/"
2514 };
2515
2516 int i;
2517
2518 const int imax = ARRAYELTS (tempdirs);
2519
2520 /* Implementation note: This function explicitly works with ANSI
2521 file names, not with UTF-8 encoded file names. This is because
2522 this function pushes variables into the Emacs's environment, and
2523 the environment variables are always assumed to be in the
2524 locale-specific encoding. Do NOT call any functions that accept
2525 UTF-8 file names from this function! */
2526
2527 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
2528 temporary files and assume "/tmp" if $TMPDIR is unset, which
2529 will break on DOS/Windows. Refuse to work if we cannot find
2530 a directory, not even "c:/", usable for that purpose. */
2531 for (i = 0; i < imax ; i++)
2532 {
2533 const char *tmp = tempdirs[i];
2534
2535 if (*tmp == '$')
2536 tmp = getenv (tmp + 1);
2537 /* Note that `access' can lie to us if the directory resides on a
2538 read-only filesystem, like CD-ROM or a write-protected floppy.
2539 The only way to be really sure is to actually create a file and
2540 see if it succeeds. But I think that's too much to ask. */
2541
2542 /* MSVCRT's _access crashes with D_OK, so we use our replacement. */
2543 if (tmp && sys_access (tmp, D_OK) == 0)
2544 {
2545 char * var = alloca (strlen (tmp) + 8);
2546 sprintf (var, "TMPDIR=%s", tmp);
2547 _putenv (strdup (var));
2548 break;
2549 }
2550 }
2551 if (i >= imax)
2552 cmd_error_internal
2553 (Fcons (Qerror,
2554 Fcons (build_string ("no usable temporary directories found!!"),
2555 Qnil)),
2556 "While setting TMPDIR: ");
2557
2558 /* Check for environment variables and use registry settings if they
2559 don't exist. Fallback on default values where applicable. */
2560 {
2561 int i;
2562 LPBYTE lpval;
2563 DWORD dwType;
2564 char locale_name[32];
2565 char default_home[MAX_PATH];
2566 int appdata = 0;
2567
2568 static const struct env_entry
2569 {
2570 char * name;
2571 char * def_value;
2572 } dflt_envvars[] =
2573 {
2574 /* If the default value is NULL, we will use the value from the
2575 outside environment or the Registry, but will not push the
2576 variable into the Emacs environment if it is defined neither
2577 in the Registry nor in the outside environment. */
2578 {"HOME", "C:/"},
2579 {"PRELOAD_WINSOCK", NULL},
2580 {"emacs_dir", "C:/emacs"},
2581 {"EMACSLOADPATH", NULL},
2582 {"SHELL", "cmdproxy.exe"}, /* perhaps it is somewhere on PATH */
2583 {"EMACSDATA", NULL},
2584 {"EMACSPATH", NULL},
2585 {"INFOPATH", NULL},
2586 {"EMACSDOC", NULL},
2587 {"TERM", "cmd"},
2588 {"LANG", NULL},
2589 };
2590
2591 #define N_ENV_VARS ARRAYELTS (dflt_envvars)
2592
2593 /* We need to copy dflt_envvars[] and work on the copy because we
2594 don't want the dumped Emacs to inherit the values of
2595 environment variables we saw during dumping (which could be on
2596 a different system). The defaults above must be left intact. */
2597 struct env_entry env_vars[N_ENV_VARS];
2598
2599 for (i = 0; i < N_ENV_VARS; i++)
2600 env_vars[i] = dflt_envvars[i];
2601
2602 /* For backwards compatibility, check if a .emacs file exists in C:/
2603 If not, then we can try to default to the appdata directory under the
2604 user's profile, which is more likely to be writable. */
2605 if (sys_access ("C:/.emacs", F_OK) != 0)
2606 {
2607 HRESULT profile_result;
2608 /* Dynamically load ShGetFolderPath, as it won't exist on versions
2609 of Windows 95 and NT4 that have not been updated to include
2610 MSIE 5. */
2611 ShGetFolderPath_fn get_folder_path;
2612 get_folder_path = (ShGetFolderPath_fn)
2613 GetProcAddress (GetModuleHandle ("shell32.dll"), "SHGetFolderPathA");
2614
2615 if (get_folder_path != NULL)
2616 {
2617 profile_result = get_folder_path (NULL, CSIDL_APPDATA, NULL,
2618 0, default_home);
2619
2620 /* If we can't get the appdata dir, revert to old behavior. */
2621 if (profile_result == S_OK)
2622 {
2623 env_vars[0].def_value = default_home;
2624 appdata = 1;
2625 }
2626 }
2627 }
2628
2629 /* Get default locale info and use it for LANG. */
2630 if (GetLocaleInfo (LOCALE_USER_DEFAULT,
2631 LOCALE_SABBREVLANGNAME | LOCALE_USE_CP_ACP,
2632 locale_name, sizeof (locale_name)))
2633 {
2634 for (i = 0; i < N_ENV_VARS; i++)
2635 {
2636 if (strcmp (env_vars[i].name, "LANG") == 0)
2637 {
2638 env_vars[i].def_value = locale_name;
2639 break;
2640 }
2641 }
2642 }
2643
2644 #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
2645
2646 /* Treat emacs_dir specially: set it unconditionally based on our
2647 location. */
2648 {
2649 char *p;
2650 char modname[MAX_PATH];
2651
2652 if (!GetModuleFileNameA (NULL, modname, MAX_PATH))
2653 emacs_abort ();
2654 if ((p = _mbsrchr (modname, '\\')) == NULL)
2655 emacs_abort ();
2656 *p = 0;
2657
2658 if ((p = _mbsrchr (modname, '\\'))
2659 /* From bin means installed Emacs, from src means uninstalled. */
2660 && (xstrcasecmp (p, "\\bin") == 0 || xstrcasecmp (p, "\\src") == 0))
2661 {
2662 char buf[SET_ENV_BUF_SIZE];
2663 int within_build_tree = xstrcasecmp (p, "\\src") == 0;
2664
2665 *p = 0;
2666 for (p = modname; *p; p = CharNext (p))
2667 if (*p == '\\') *p = '/';
2668
2669 _snprintf (buf, sizeof (buf)-1, "emacs_dir=%s", modname);
2670 _putenv (strdup (buf));
2671 /* If we are running from the Posix-like build tree, define
2672 SHELL to point to our own cmdproxy. The loop below will
2673 then disregard PATH_EXEC and the default value. */
2674 if (within_build_tree)
2675 {
2676 _snprintf (buf, sizeof (buf) - 1,
2677 "SHELL=%s/nt/cmdproxy.exe", modname);
2678 _putenv (strdup (buf));
2679 }
2680 }
2681 }
2682
2683 for (i = 0; i < N_ENV_VARS; i++)
2684 {
2685 if (!getenv (env_vars[i].name))
2686 {
2687 int dont_free = 0;
2688 char bufc[SET_ENV_BUF_SIZE];
2689
2690 if ((lpval = w32_get_resource (env_vars[i].name, &dwType)) == NULL
2691 /* Also ignore empty environment variables. */
2692 || *lpval == 0)
2693 {
2694 xfree (lpval);
2695 dont_free = 1;
2696 if (strcmp (env_vars[i].name, "SHELL") == 0)
2697 {
2698 /* Look for cmdproxy.exe in every directory in
2699 PATH_EXEC. FIXME: This does not find cmdproxy
2700 in nt/ when we run uninstalled. */
2701 char fname[MAX_PATH];
2702 const char *pstart = PATH_EXEC, *pend;
2703
2704 do {
2705 pend = _mbschr (pstart, ';');
2706 if (!pend)
2707 pend = pstart + strlen (pstart);
2708 /* Be defensive against series of ;;; characters. */
2709 if (pend > pstart)
2710 {
2711 strncpy (fname, pstart, pend - pstart);
2712 fname[pend - pstart] = '/';
2713 strcpy (&fname[pend - pstart + 1], "cmdproxy.exe");
2714 ExpandEnvironmentStrings ((LPSTR) fname, bufc,
2715 sizeof (bufc));
2716 if (sys_access (bufc, F_OK) == 0)
2717 {
2718 lpval = bufc;
2719 dwType = REG_SZ;
2720 break;
2721 }
2722 }
2723 if (*pend)
2724 pstart = pend + 1;
2725 else
2726 pstart = pend;
2727 if (!*pstart)
2728 {
2729 /* If not found in any directory, use the
2730 default as the last resort. */
2731 lpval = env_vars[i].def_value;
2732 dwType = REG_EXPAND_SZ;
2733 }
2734 } while (*pstart);
2735 }
2736 else
2737 {
2738 lpval = env_vars[i].def_value;
2739 dwType = REG_EXPAND_SZ;
2740 }
2741 if (strcmp (env_vars[i].name, "HOME") == 0 && !appdata)
2742 Vdelayed_warnings_list
2743 = Fcons (listn (CONSTYPE_HEAP, 2,
2744 intern ("initialization"),
2745 build_string ("Setting HOME to C:\\ by default is deprecated")),
2746 Vdelayed_warnings_list);
2747 }
2748
2749 if (lpval)
2750 {
2751 char buf1[SET_ENV_BUF_SIZE], buf2[SET_ENV_BUF_SIZE];
2752
2753 if (dwType == REG_EXPAND_SZ)
2754 ExpandEnvironmentStrings ((LPSTR) lpval, buf1, sizeof (buf1));
2755 else if (dwType == REG_SZ)
2756 strcpy (buf1, lpval);
2757 if (dwType == REG_EXPAND_SZ || dwType == REG_SZ)
2758 {
2759 _snprintf (buf2, sizeof (buf2)-1, "%s=%s", env_vars[i].name,
2760 buf1);
2761 _putenv (strdup (buf2));
2762 }
2763
2764 if (!dont_free)
2765 xfree (lpval);
2766 }
2767 }
2768 }
2769 }
2770
2771 /* Rebuild system configuration to reflect invoking system. */
2772 Vsystem_configuration = build_string (EMACS_CONFIGURATION);
2773
2774 /* Another special case: on NT, the PATH variable is actually named
2775 "Path" although cmd.exe (perhaps NT itself) arranges for
2776 environment variable lookup and setting to be case insensitive.
2777 However, Emacs assumes a fully case sensitive environment, so we
2778 need to change "Path" to "PATH" to match the expectations of
2779 various elisp packages. We do this by the sneaky method of
2780 modifying the string in the C runtime environ entry.
2781
2782 The same applies to COMSPEC. */
2783 {
2784 char ** envp;
2785
2786 for (envp = environ; *envp; envp++)
2787 if (_strnicmp (*envp, "PATH=", 5) == 0)
2788 memcpy (*envp, "PATH=", 5);
2789 else if (_strnicmp (*envp, "COMSPEC=", 8) == 0)
2790 memcpy (*envp, "COMSPEC=", 8);
2791 }
2792
2793 /* Remember the initial working directory for getcwd. */
2794 /* FIXME: Do we need to resolve possible symlinks in startup_dir?
2795 Does it matter anywhere in Emacs? */
2796 if (w32_unicode_filenames)
2797 {
2798 wchar_t wstartup_dir[MAX_PATH];
2799
2800 if (!GetCurrentDirectoryW (MAX_PATH, wstartup_dir))
2801 emacs_abort ();
2802 filename_from_utf16 (wstartup_dir, startup_dir);
2803 }
2804 else
2805 {
2806 char astartup_dir[MAX_PATH];
2807
2808 if (!GetCurrentDirectoryA (MAX_PATH, astartup_dir))
2809 emacs_abort ();
2810 filename_from_ansi (astartup_dir, startup_dir);
2811 }
2812
2813 {
2814 static char modname[MAX_PATH];
2815
2816 if (!GetModuleFileNameA (NULL, modname, MAX_PATH))
2817 emacs_abort ();
2818 argv[0] = modname;
2819 }
2820
2821 /* Determine if there is a middle mouse button, to allow parse_button
2822 to decide whether right mouse events should be mouse-2 or
2823 mouse-3. */
2824 w32_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);
2825
2826 init_user_info ();
2827 }
2828
2829 /* Called from expand-file-name when default-directory is not a string. */
2830
2831 char *
2832 emacs_root_dir (void)
2833 {
2834 static char root_dir[MAX_UTF8_PATH];
2835 const char *p;
2836
2837 p = getenv ("emacs_dir");
2838 if (p == NULL)
2839 emacs_abort ();
2840 filename_from_ansi (p, root_dir);
2841 root_dir[parse_root (root_dir, NULL)] = '\0';
2842 dostounix_filename (root_dir);
2843 return root_dir;
2844 }
2845
2846 #include <sys/timeb.h>
2847
2848 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
2849 int
2850 gettimeofday (struct timeval *__restrict tv, struct timezone *__restrict tz)
2851 {
2852 struct _timeb tb;
2853 _ftime (&tb);
2854
2855 tv->tv_sec = tb.time;
2856 tv->tv_usec = tb.millitm * 1000L;
2857 /* Implementation note: _ftime sometimes doesn't update the dstflag
2858 according to the new timezone when the system timezone is
2859 changed. We could fix that by using GetSystemTime and
2860 GetTimeZoneInformation, but that doesn't seem necessary, since
2861 Emacs always calls gettimeofday with the 2nd argument NULL (see
2862 current_emacs_time). */
2863 if (tz)
2864 {
2865 tz->tz_minuteswest = tb.timezone; /* minutes west of Greenwich */
2866 tz->tz_dsttime = tb.dstflag; /* type of dst correction */
2867 }
2868 return 0;
2869 }
2870
2871 /* Emulate fdutimens. */
2872
2873 /* Set the access and modification time stamps of FD (a.k.a. FILE) to be
2874 TIMESPEC[0] and TIMESPEC[1], respectively.
2875 FD must be either negative -- in which case it is ignored --
2876 or a file descriptor that is open on FILE.
2877 If FD is nonnegative, then FILE can be NULL, which means
2878 use just futimes instead of utimes.
2879 If TIMESPEC is null, FAIL.
2880 Return 0 on success, -1 (setting errno) on failure. */
2881
2882 int
2883 fdutimens (int fd, char const *file, struct timespec const timespec[2])
2884 {
2885 if (!timespec)
2886 {
2887 errno = ENOSYS;
2888 return -1;
2889 }
2890 if (fd < 0 && !file)
2891 {
2892 errno = EBADF;
2893 return -1;
2894 }
2895 /* _futime's prototype defines 2nd arg as having the type 'struct
2896 _utimbuf', while utime needs to accept 'struct utimbuf' for
2897 compatibility with Posix. So we need to use 2 different (but
2898 equivalent) types to avoid compiler warnings, sigh. */
2899 if (fd >= 0)
2900 {
2901 struct _utimbuf _ut;
2902
2903 _ut.actime = timespec[0].tv_sec;
2904 _ut.modtime = timespec[1].tv_sec;
2905 return _futime (fd, &_ut);
2906 }
2907 else
2908 {
2909 struct utimbuf ut;
2910
2911 ut.actime = timespec[0].tv_sec;
2912 ut.modtime = timespec[1].tv_sec;
2913 /* Call 'utime', which is implemented below, not the MS library
2914 function, which fails on directories. */
2915 return utime (file, &ut);
2916 }
2917 }
2918
2919
2920 /* ------------------------------------------------------------------------- */
2921 /* IO support and wrapper functions for the Windows API. */
2922 /* ------------------------------------------------------------------------- */
2923
2924 /* Place a wrapper around the MSVC version of ctime. It returns NULL
2925 on network directories, so we handle that case here.
2926 (Ulrich Leodolter, 1/11/95). */
2927 char *
2928 sys_ctime (const time_t *t)
2929 {
2930 char *str = (char *) ctime (t);
2931 return (str ? str : "Sun Jan 01 00:00:00 1970");
2932 }
2933
2934 /* Emulate sleep...we could have done this with a define, but that
2935 would necessitate including windows.h in the files that used it.
2936 This is much easier. */
2937 void
2938 sys_sleep (int seconds)
2939 {
2940 Sleep (seconds * 1000);
2941 }
2942
2943 /* Internal MSVC functions for low-level descriptor munging */
2944 extern int __cdecl _set_osfhnd (int fd, long h);
2945 extern int __cdecl _free_osfhnd (int fd);
2946
2947 /* parallel array of private info on file handles */
2948 filedesc fd_info [ MAXDESC ];
2949
2950 typedef struct volume_info_data {
2951 struct volume_info_data * next;
2952
2953 /* time when info was obtained */
2954 DWORD timestamp;
2955
2956 /* actual volume info */
2957 char * root_dir;
2958 DWORD serialnum;
2959 DWORD maxcomp;
2960 DWORD flags;
2961 char * name;
2962 char * type;
2963 } volume_info_data;
2964
2965 /* Global referenced by various functions. */
2966 static volume_info_data volume_info;
2967
2968 /* Vector to indicate which drives are local and fixed (for which cached
2969 data never expires). */
2970 static BOOL fixed_drives[26];
2971
2972 /* Consider cached volume information to be stale if older than 10s,
2973 at least for non-local drives. Info for fixed drives is never stale. */
2974 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
2975 #define VOLINFO_STILL_VALID( root_dir, info ) \
2976 ( ( isalpha (root_dir[0]) && \
2977 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
2978 || GetTickCount () - info->timestamp < 10000 )
2979
2980 /* Cache support functions. */
2981
2982 /* Simple linked list with linear search is sufficient. */
2983 static volume_info_data *volume_cache = NULL;
2984
2985 static volume_info_data *
2986 lookup_volume_info (char * root_dir)
2987 {
2988 volume_info_data * info;
2989
2990 for (info = volume_cache; info; info = info->next)
2991 if (xstrcasecmp (info->root_dir, root_dir) == 0)
2992 break;
2993 return info;
2994 }
2995
2996 static void
2997 add_volume_info (char * root_dir, volume_info_data * info)
2998 {
2999 info->root_dir = xstrdup (root_dir);
3000 unixtodos_filename (info->root_dir);
3001 info->next = volume_cache;
3002 volume_cache = info;
3003 }
3004
3005
3006 /* Wrapper for GetVolumeInformation, which uses caching to avoid
3007 performance penalty (~2ms on 486 for local drives, 7.5ms for local
3008 cdrom drive, ~5-10ms or more for remote drives on LAN). */
3009 static volume_info_data *
3010 GetCachedVolumeInformation (char * root_dir)
3011 {
3012 volume_info_data * info;
3013 char default_root[ MAX_UTF8_PATH ];
3014 char name[MAX_PATH+1];
3015 char type[MAX_PATH+1];
3016
3017 /* NULL for root_dir means use root from current directory. */
3018 if (root_dir == NULL)
3019 {
3020 if (w32_unicode_filenames)
3021 {
3022 wchar_t curdirw[MAX_PATH];
3023
3024 if (GetCurrentDirectoryW (MAX_PATH, curdirw) == 0)
3025 return NULL;
3026 filename_from_utf16 (curdirw, default_root);
3027 }
3028 else
3029 {
3030 char curdira[MAX_PATH];
3031
3032 if (GetCurrentDirectoryA (MAX_PATH, curdira) == 0)
3033 return NULL;
3034 filename_from_ansi (curdira, default_root);
3035 }
3036 parse_root (default_root, (const char **)&root_dir);
3037 *root_dir = 0;
3038 root_dir = default_root;
3039 }
3040
3041 /* Local fixed drives can be cached permanently. Removable drives
3042 cannot be cached permanently, since the volume name and serial
3043 number (if nothing else) can change. Remote drives should be
3044 treated as if they are removable, since there is no sure way to
3045 tell whether they are or not. Also, the UNC association of drive
3046 letters mapped to remote volumes can be changed at any time (even
3047 by other processes) without notice.
3048
3049 As a compromise, so we can benefit from caching info for remote
3050 volumes, we use a simple expiry mechanism to invalidate cache
3051 entries that are more than ten seconds old. */
3052
3053 #if 0
3054 /* No point doing this, because WNetGetConnection is even slower than
3055 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
3056 GetDriveType is about the only call of this type which does not
3057 involve network access, and so is extremely quick). */
3058
3059 /* Map drive letter to UNC if remote. */
3060 if (isalpha (root_dir[0]) && !fixed[DRIVE_INDEX (root_dir[0])])
3061 {
3062 char remote_name[ 256 ];
3063 char drive[3] = { root_dir[0], ':' };
3064
3065 if (WNetGetConnection (drive, remote_name, sizeof (remote_name))
3066 == NO_ERROR)
3067 /* do something */ ;
3068 }
3069 #endif
3070
3071 info = lookup_volume_info (root_dir);
3072
3073 if (info == NULL || ! VOLINFO_STILL_VALID (root_dir, info))
3074 {
3075 DWORD serialnum;
3076 DWORD maxcomp;
3077 DWORD flags;
3078
3079 /* Info is not cached, or is stale. */
3080 if (w32_unicode_filenames)
3081 {
3082 wchar_t root_w[MAX_PATH];
3083 wchar_t name_w[MAX_PATH+1];
3084 wchar_t type_w[MAX_PATH+1];
3085
3086 filename_to_utf16 (root_dir, root_w);
3087 if (!GetVolumeInformationW (root_w,
3088 name_w, sizeof (name_w),
3089 &serialnum,
3090 &maxcomp,
3091 &flags,
3092 type_w, sizeof (type_w)))
3093 return NULL;
3094 /* Hmm... not really 100% correct, as these 2 are not file
3095 names... */
3096 filename_from_utf16 (name_w, name);
3097 filename_from_utf16 (type_w, type);
3098 }
3099 else
3100 {
3101 char root_a[MAX_PATH];
3102 char name_a[MAX_PATH+1];
3103 char type_a[MAX_PATH+1];
3104
3105 filename_to_ansi (root_dir, root_a);
3106 if (!GetVolumeInformationA (root_a,
3107 name_a, sizeof (name_a),
3108 &serialnum,
3109 &maxcomp,
3110 &flags,
3111 type_a, sizeof (type_a)))
3112 return NULL;
3113 filename_from_ansi (name_a, name);
3114 filename_from_ansi (type_a, type);
3115 }
3116
3117 /* Cache the volume information for future use, overwriting existing
3118 entry if present. */
3119 if (info == NULL)
3120 {
3121 info = xmalloc (sizeof (volume_info_data));
3122 add_volume_info (root_dir, info);
3123 }
3124 else
3125 {
3126 xfree (info->name);
3127 xfree (info->type);
3128 }
3129
3130 info->name = xstrdup (name);
3131 unixtodos_filename (info->name);
3132 info->serialnum = serialnum;
3133 info->maxcomp = maxcomp;
3134 info->flags = flags;
3135 info->type = xstrdup (type);
3136 info->timestamp = GetTickCount ();
3137 }
3138
3139 return info;
3140 }
3141
3142 /* Get information on the volume where NAME is held; set path pointer to
3143 start of pathname in NAME (past UNC header\volume header if present),
3144 if pPath is non-NULL.
3145
3146 Note: if NAME includes symlinks, the information is for the volume
3147 of the symlink, not of its target. That's because, even though
3148 GetVolumeInformation returns information about the symlink target
3149 of its argument, we only pass the root directory to
3150 GetVolumeInformation, not the full NAME. */
3151 static int
3152 get_volume_info (const char * name, const char ** pPath)
3153 {
3154 char temp[MAX_UTF8_PATH];
3155 char *rootname = NULL; /* default to current volume */
3156 volume_info_data * info;
3157 int root_len = parse_root (name, pPath);
3158
3159 if (name == NULL)
3160 return FALSE;
3161
3162 /* Copy the root name of the volume, if given. */
3163 if (root_len)
3164 {
3165 strncpy (temp, name, root_len);
3166 temp[root_len] = '\0';
3167 unixtodos_filename (temp);
3168 rootname = temp;
3169 }
3170
3171 info = GetCachedVolumeInformation (rootname);
3172 if (info != NULL)
3173 {
3174 /* Set global referenced by other functions. */
3175 volume_info = *info;
3176 return TRUE;
3177 }
3178 return FALSE;
3179 }
3180
3181 /* Determine if volume is FAT format (ie. only supports short 8.3
3182 names); also set path pointer to start of pathname in name, if
3183 pPath is non-NULL. */
3184 static int
3185 is_fat_volume (const char * name, const char ** pPath)
3186 {
3187 if (get_volume_info (name, pPath))
3188 return (volume_info.maxcomp == 12);
3189 return FALSE;
3190 }
3191
3192 /* Convert all slashes in a filename to backslashes, and map filename
3193 to a valid 8.3 name if necessary. The result is a pointer to a
3194 static buffer, so CAVEAT EMPTOR! */
3195 const char *
3196 map_w32_filename (const char * name, const char ** pPath)
3197 {
3198 static char shortname[MAX_UTF8_PATH];
3199 char * str = shortname;
3200 char c;
3201 char * path;
3202 const char * save_name = name;
3203
3204 if (strlen (name) >= sizeof (shortname))
3205 {
3206 /* Return a filename which will cause callers to fail. */
3207 strcpy (shortname, "?");
3208 return shortname;
3209 }
3210
3211 if (is_fat_volume (name, (const char **)&path)) /* truncate to 8.3 */
3212 {
3213 register int left = 8; /* maximum number of chars in part */
3214 register int extn = 0; /* extension added? */
3215 register int dots = 2; /* maximum number of dots allowed */
3216
3217 while (name < path)
3218 *str++ = *name++; /* skip past UNC header */
3219
3220 while ((c = *name++))
3221 {
3222 switch ( c )
3223 {
3224 case ':':
3225 case '\\':
3226 case '/':
3227 *str++ = (c == ':' ? ':' : '\\');
3228 extn = 0; /* reset extension flags */
3229 dots = 2; /* max 2 dots */
3230 left = 8; /* max length 8 for main part */
3231 break;
3232 case '.':
3233 if ( dots )
3234 {
3235 /* Convert path components of the form .xxx to _xxx,
3236 but leave . and .. as they are. This allows .emacs
3237 to be read as _emacs, for example. */
3238
3239 if (! *name ||
3240 *name == '.' ||
3241 IS_DIRECTORY_SEP (*name))
3242 {
3243 *str++ = '.';
3244 dots--;
3245 }
3246 else
3247 {
3248 *str++ = '_';
3249 left--;
3250 dots = 0;
3251 }
3252 }
3253 else if ( !extn )
3254 {
3255 *str++ = '.';
3256 extn = 1; /* we've got an extension */
3257 left = 3; /* 3 chars in extension */
3258 }
3259 else
3260 {
3261 /* any embedded dots after the first are converted to _ */
3262 *str++ = '_';
3263 }
3264 break;
3265 case '~':
3266 case '#': /* don't lose these, they're important */
3267 if ( ! left )
3268 str[-1] = c; /* replace last character of part */
3269 /* FALLTHRU */
3270 default:
3271 if ( left && 'A' <= c && c <= 'Z' )
3272 {
3273 *str++ = tolower (c); /* map to lower case (looks nicer) */
3274 left--;
3275 dots = 0; /* started a path component */
3276 }
3277 break;
3278 }
3279 }
3280 *str = '\0';
3281 }
3282 else
3283 {
3284 strcpy (shortname, name);
3285 unixtodos_filename (shortname);
3286 }
3287
3288 if (pPath)
3289 *pPath = shortname + (path - save_name);
3290
3291 return shortname;
3292 }
3293
3294 static int
3295 is_exec (const char * name)
3296 {
3297 char * p = strrchr (name, '.');
3298 return
3299 (p != NULL
3300 && (xstrcasecmp (p, ".exe") == 0 ||
3301 xstrcasecmp (p, ".com") == 0 ||
3302 xstrcasecmp (p, ".bat") == 0 ||
3303 xstrcasecmp (p, ".cmd") == 0));
3304 }
3305
3306 /* Emulate the Unix directory procedures opendir, closedir, and
3307 readdir. We rename them to sys_* names because some versions of
3308 MinGW startup code call opendir and readdir to glob wildcards, and
3309 the code that calls them doesn't grok UTF-8 encoded file names we
3310 produce in dirent->d_name[]. */
3311
3312 struct dirent dir_static; /* simulated directory contents */
3313 static HANDLE dir_find_handle = INVALID_HANDLE_VALUE;
3314 static int dir_is_fat;
3315 static char dir_pathname[MAX_UTF8_PATH];
3316 static WIN32_FIND_DATAW dir_find_data_w;
3317 static WIN32_FIND_DATAA dir_find_data_a;
3318 #define DIR_FIND_DATA_W 1
3319 #define DIR_FIND_DATA_A 2
3320 static int last_dir_find_data = -1;
3321
3322 /* Support shares on a network resource as subdirectories of a read-only
3323 root directory. */
3324 static HANDLE wnet_enum_handle = INVALID_HANDLE_VALUE;
3325 static HANDLE open_unc_volume (const char *);
3326 static void *read_unc_volume (HANDLE, wchar_t *, char *, int);
3327 static void close_unc_volume (HANDLE);
3328
3329 DIR *
3330 sys_opendir (const char *filename)
3331 {
3332 DIR *dirp;
3333
3334 /* Opening is done by FindFirstFile. However, a read is inherent to
3335 this operation, so we defer the open until read time. */
3336
3337 if (dir_find_handle != INVALID_HANDLE_VALUE)
3338 return NULL;
3339 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
3340 return NULL;
3341
3342 /* Note: We don't support traversal of UNC volumes via symlinks.
3343 Doing so would mean punishing 99.99% of use cases by resolving
3344 all the possible symlinks in FILENAME, recursively. */
3345 if (is_unc_volume (filename))
3346 {
3347 wnet_enum_handle = open_unc_volume (filename);
3348 if (wnet_enum_handle == INVALID_HANDLE_VALUE)
3349 return NULL;
3350 }
3351
3352 if (!(dirp = (DIR *) malloc (sizeof (DIR))))
3353 return NULL;
3354
3355 dirp->dd_fd = 0;
3356 dirp->dd_loc = 0;
3357 dirp->dd_size = 0;
3358
3359 strncpy (dir_pathname, map_w32_filename (filename, NULL), MAX_UTF8_PATH - 1);
3360 dir_pathname[MAX_UTF8_PATH - 1] = '\0';
3361 /* Note: We don't support symlinks to file names on FAT volumes.
3362 Doing so would mean punishing 99.99% of use cases by resolving
3363 all the possible symlinks in FILENAME, recursively. */
3364 dir_is_fat = is_fat_volume (filename, NULL);
3365
3366 return dirp;
3367 }
3368
3369 void
3370 sys_closedir (DIR *dirp)
3371 {
3372 /* If we have a find-handle open, close it. */
3373 if (dir_find_handle != INVALID_HANDLE_VALUE)
3374 {
3375 FindClose (dir_find_handle);
3376 dir_find_handle = INVALID_HANDLE_VALUE;
3377 }
3378 else if (wnet_enum_handle != INVALID_HANDLE_VALUE)
3379 {
3380 close_unc_volume (wnet_enum_handle);
3381 wnet_enum_handle = INVALID_HANDLE_VALUE;
3382 }
3383 xfree ((char *) dirp);
3384 }
3385
3386 struct dirent *
3387 sys_readdir (DIR *dirp)
3388 {
3389 int downcase = !NILP (Vw32_downcase_file_names);
3390
3391 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
3392 {
3393 if (!read_unc_volume (wnet_enum_handle,
3394 dir_find_data_w.cFileName,
3395 dir_find_data_a.cFileName,
3396 MAX_PATH))
3397 return NULL;
3398 }
3399 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
3400 else if (dir_find_handle == INVALID_HANDLE_VALUE)
3401 {
3402 char filename[MAX_UTF8_PATH + 2];
3403 int ln;
3404
3405 strcpy (filename, dir_pathname);
3406 ln = strlen (filename);
3407 if (!IS_DIRECTORY_SEP (filename[ln - 1]))
3408 filename[ln++] = '\\';
3409 strcpy (filename + ln, "*");
3410
3411 /* Note: No need to resolve symlinks in FILENAME, because
3412 FindFirst opens the directory that is the target of a
3413 symlink. */
3414 if (w32_unicode_filenames)
3415 {
3416 wchar_t fnw[MAX_PATH];
3417
3418 filename_to_utf16 (filename, fnw);
3419 dir_find_handle = FindFirstFileW (fnw, &dir_find_data_w);
3420 }
3421 else
3422 {
3423 char fna[MAX_PATH];
3424
3425 filename_to_ansi (filename, fna);
3426 /* If FILENAME is not representable by the current ANSI
3427 codepage, we don't want FindFirstFileA to interpret the
3428 '?' characters as a wildcard. */
3429 if (_mbspbrk (fna, "?"))
3430 dir_find_handle = INVALID_HANDLE_VALUE;
3431 else
3432 dir_find_handle = FindFirstFileA (fna, &dir_find_data_a);
3433 }
3434
3435 if (dir_find_handle == INVALID_HANDLE_VALUE)
3436 {
3437 switch (GetLastError ())
3438 {
3439 case ERROR_PATH_NOT_FOUND:
3440 case ERROR_ACCESS_DENIED:
3441 case ERROR_INVALID_DRIVE:
3442 case ERROR_BAD_NETPATH:
3443 /* This special value will be noticed by
3444 directory_files_internal, which see. */
3445 errno = ENOTDIR;
3446 break;
3447 default:
3448 break;
3449 }
3450 return NULL;
3451 }
3452 }
3453 else if (w32_unicode_filenames)
3454 {
3455 if (!FindNextFileW (dir_find_handle, &dir_find_data_w))
3456 return NULL;
3457 }
3458 else
3459 {
3460 if (!FindNextFileA (dir_find_handle, &dir_find_data_a))
3461 return NULL;
3462 }
3463
3464 /* Emacs never uses this value, so don't bother making it match
3465 value returned by stat(). */
3466 dir_static.d_ino = 1;
3467
3468 if (w32_unicode_filenames)
3469 {
3470 if (downcase || dir_is_fat)
3471 {
3472 wchar_t tem[MAX_PATH];
3473
3474 wcscpy (tem, dir_find_data_w.cFileName);
3475 CharLowerW (tem);
3476 filename_from_utf16 (tem, dir_static.d_name);
3477 }
3478 else
3479 filename_from_utf16 (dir_find_data_w.cFileName, dir_static.d_name);
3480 last_dir_find_data = DIR_FIND_DATA_W;
3481 }
3482 else
3483 {
3484 char tem[MAX_PATH];
3485
3486 /* If the file name in cFileName[] includes `?' characters, it
3487 means the original file name used characters that cannot be
3488 represented by the current ANSI codepage. To avoid total
3489 lossage, retrieve the short 8+3 alias of the long file
3490 name. */
3491 if (_mbspbrk (dir_find_data_a.cFileName, "?"))
3492 {
3493 strcpy (tem, dir_find_data_a.cAlternateFileName);
3494 /* 8+3 aliases are returned in all caps, which could break
3495 various alists that look at filenames' extensions. */
3496 downcase = 1;
3497 }
3498 else if (downcase || dir_is_fat)
3499 strcpy (tem, dir_find_data_a.cFileName);
3500 else
3501 filename_from_ansi (dir_find_data_a.cFileName, dir_static.d_name);
3502 if (downcase || dir_is_fat)
3503 {
3504 _mbslwr (tem);
3505 filename_from_ansi (tem, dir_static.d_name);
3506 }
3507 last_dir_find_data = DIR_FIND_DATA_A;
3508 }
3509
3510 dir_static.d_namlen = strlen (dir_static.d_name);
3511 dir_static.d_reclen = sizeof (struct dirent) - MAX_UTF8_PATH + 3 +
3512 dir_static.d_namlen - dir_static.d_namlen % 4;
3513
3514 return &dir_static;
3515 }
3516
3517 static HANDLE
3518 open_unc_volume (const char *path)
3519 {
3520 const char *fn = map_w32_filename (path, NULL);
3521 DWORD result;
3522 HANDLE henum;
3523
3524 if (w32_unicode_filenames)
3525 {
3526 NETRESOURCEW nrw;
3527 wchar_t fnw[MAX_PATH];
3528
3529 nrw.dwScope = RESOURCE_GLOBALNET;
3530 nrw.dwType = RESOURCETYPE_DISK;
3531 nrw.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
3532 nrw.dwUsage = RESOURCEUSAGE_CONTAINER;
3533 nrw.lpLocalName = NULL;
3534 filename_to_utf16 (fn, fnw);
3535 nrw.lpRemoteName = fnw;
3536 nrw.lpComment = NULL;
3537 nrw.lpProvider = NULL;
3538
3539 result = WNetOpenEnumW (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
3540 RESOURCEUSAGE_CONNECTABLE, &nrw, &henum);
3541 }
3542 else
3543 {
3544 NETRESOURCEA nra;
3545 char fna[MAX_PATH];
3546
3547 nra.dwScope = RESOURCE_GLOBALNET;
3548 nra.dwType = RESOURCETYPE_DISK;
3549 nra.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
3550 nra.dwUsage = RESOURCEUSAGE_CONTAINER;
3551 nra.lpLocalName = NULL;
3552 filename_to_ansi (fn, fna);
3553 nra.lpRemoteName = fna;
3554 nra.lpComment = NULL;
3555 nra.lpProvider = NULL;
3556
3557 result = WNetOpenEnumA (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
3558 RESOURCEUSAGE_CONNECTABLE, &nra, &henum);
3559 }
3560 if (result == NO_ERROR)
3561 return henum;
3562 else
3563 return INVALID_HANDLE_VALUE;
3564 }
3565
3566 static void *
3567 read_unc_volume (HANDLE henum, wchar_t *fname_w, char *fname_a, int size)
3568 {
3569 DWORD count;
3570 int result;
3571 char *buffer;
3572 DWORD bufsize = 512;
3573 void *retval;
3574
3575 count = 1;
3576 if (w32_unicode_filenames)
3577 {
3578 wchar_t *ptrw;
3579
3580 bufsize *= 2;
3581 buffer = alloca (bufsize);
3582 result = WNetEnumResourceW (henum, &count, buffer, &bufsize);
3583 if (result != NO_ERROR)
3584 return NULL;
3585 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
3586 ptrw = ((LPNETRESOURCEW) buffer)->lpRemoteName;
3587 ptrw += 2;
3588 while (*ptrw && *ptrw != L'/' && *ptrw != L'\\') ptrw++;
3589 ptrw++;
3590 wcsncpy (fname_w, ptrw, size);
3591 retval = fname_w;
3592 }
3593 else
3594 {
3595 int dbcs_p = max_filename_mbslen () > 1;
3596 char *ptra;
3597
3598 buffer = alloca (bufsize);
3599 result = WNetEnumResourceA (henum, &count, buffer, &bufsize);
3600 if (result != NO_ERROR)
3601 return NULL;
3602 ptra = ((LPNETRESOURCEA) buffer)->lpRemoteName;
3603 ptra += 2;
3604 if (!dbcs_p)
3605 while (*ptra && !IS_DIRECTORY_SEP (*ptra)) ptra++;
3606 else
3607 {
3608 while (*ptra && !IS_DIRECTORY_SEP (*ptra))
3609 ptra = CharNextExA (file_name_codepage, ptra, 0);
3610 }
3611 ptra++;
3612 strncpy (fname_a, ptra, size);
3613 retval = fname_a;
3614 }
3615
3616 return retval;
3617 }
3618
3619 static void
3620 close_unc_volume (HANDLE henum)
3621 {
3622 if (henum != INVALID_HANDLE_VALUE)
3623 WNetCloseEnum (henum);
3624 }
3625
3626 static DWORD
3627 unc_volume_file_attributes (const char *path)
3628 {
3629 HANDLE henum;
3630 DWORD attrs;
3631
3632 henum = open_unc_volume (path);
3633 if (henum == INVALID_HANDLE_VALUE)
3634 return -1;
3635
3636 attrs = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY;
3637
3638 close_unc_volume (henum);
3639
3640 return attrs;
3641 }
3642
3643 /* Ensure a network connection is authenticated. */
3644 static void
3645 logon_network_drive (const char *path)
3646 {
3647 char share[MAX_UTF8_PATH];
3648 int n_slashes;
3649 char drive[4];
3650 UINT drvtype;
3651 char *p;
3652 DWORD val;
3653
3654 if (IS_DIRECTORY_SEP (path[0]) && IS_DIRECTORY_SEP (path[1]))
3655 drvtype = DRIVE_REMOTE;
3656 else if (path[0] == '\0' || path[1] != ':')
3657 drvtype = GetDriveType (NULL);
3658 else
3659 {
3660 drive[0] = path[0];
3661 drive[1] = ':';
3662 drive[2] = '\\';
3663 drive[3] = '\0';
3664 drvtype = GetDriveType (drive);
3665 }
3666
3667 /* Only logon to networked drives. */
3668 if (drvtype != DRIVE_REMOTE)
3669 return;
3670
3671 n_slashes = 2;
3672 strncpy (share, path, MAX_UTF8_PATH);
3673 /* Truncate to just server and share name. */
3674 for (p = share + 2; *p && p < share + MAX_UTF8_PATH; p++)
3675 {
3676 if (IS_DIRECTORY_SEP (*p) && ++n_slashes > 3)
3677 {
3678 *p = '\0';
3679 break;
3680 }
3681 }
3682
3683 if (w32_unicode_filenames)
3684 {
3685 NETRESOURCEW resourcew;
3686 wchar_t share_w[MAX_PATH];
3687
3688 resourcew.dwScope = RESOURCE_GLOBALNET;
3689 resourcew.dwType = RESOURCETYPE_DISK;
3690 resourcew.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
3691 resourcew.dwUsage = RESOURCEUSAGE_CONTAINER;
3692 resourcew.lpLocalName = NULL;
3693 filename_to_utf16 (share, share_w);
3694 resourcew.lpRemoteName = share_w;
3695 resourcew.lpProvider = NULL;
3696
3697 val = WNetAddConnection2W (&resourcew, NULL, NULL, CONNECT_INTERACTIVE);
3698 }
3699 else
3700 {
3701 NETRESOURCEA resourcea;
3702 char share_a[MAX_PATH];
3703
3704 resourcea.dwScope = RESOURCE_GLOBALNET;
3705 resourcea.dwType = RESOURCETYPE_DISK;
3706 resourcea.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
3707 resourcea.dwUsage = RESOURCEUSAGE_CONTAINER;
3708 resourcea.lpLocalName = NULL;
3709 filename_to_ansi (share, share_a);
3710 resourcea.lpRemoteName = share_a;
3711 resourcea.lpProvider = NULL;
3712
3713 val = WNetAddConnection2A (&resourcea, NULL, NULL, CONNECT_INTERACTIVE);
3714 }
3715
3716 switch (val)
3717 {
3718 case NO_ERROR:
3719 case ERROR_ALREADY_ASSIGNED:
3720 break;
3721 case ERROR_ACCESS_DENIED:
3722 case ERROR_LOGON_FAILURE:
3723 errno = EACCES;
3724 break;
3725 case ERROR_BUSY:
3726 errno = EAGAIN;
3727 break;
3728 case ERROR_BAD_NET_NAME:
3729 case ERROR_NO_NET_OR_BAD_PATH:
3730 case ERROR_NO_NETWORK:
3731 case ERROR_CANCELLED:
3732 default:
3733 errno = ENOENT;
3734 break;
3735 }
3736 }
3737
3738 /* Emulate faccessat(2). */
3739 int
3740 faccessat (int dirfd, const char * path, int mode, int flags)
3741 {
3742 DWORD attributes;
3743
3744 if (dirfd != AT_FDCWD
3745 && !(IS_DIRECTORY_SEP (path[0])
3746 || IS_DEVICE_SEP (path[1])))
3747 {
3748 errno = EBADF;
3749 return -1;
3750 }
3751
3752 /* MSVCRT implementation of 'access' doesn't recognize D_OK, and its
3753 newer versions blow up when passed D_OK. */
3754 path = map_w32_filename (path, NULL);
3755 /* If the last element of PATH is a symlink, we need to resolve it
3756 to get the attributes of its target file. Note: any symlinks in
3757 PATH elements other than the last one are transparently resolved
3758 by GetFileAttributes below. */
3759 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0
3760 && (flags & AT_SYMLINK_NOFOLLOW) == 0)
3761 path = chase_symlinks (path);
3762
3763 if (w32_unicode_filenames)
3764 {
3765 wchar_t path_w[MAX_PATH];
3766
3767 filename_to_utf16 (path, path_w);
3768 attributes = GetFileAttributesW (path_w);
3769 }
3770 else
3771 {
3772 char path_a[MAX_PATH];
3773
3774 filename_to_ansi (path, path_a);
3775 attributes = GetFileAttributesA (path_a);
3776 }
3777
3778 if (attributes == -1)
3779 {
3780 DWORD w32err = GetLastError ();
3781
3782 switch (w32err)
3783 {
3784 case ERROR_INVALID_NAME:
3785 case ERROR_BAD_PATHNAME:
3786 if (is_unc_volume (path))
3787 {
3788 attributes = unc_volume_file_attributes (path);
3789 if (attributes == -1)
3790 {
3791 errno = EACCES;
3792 return -1;
3793 }
3794 break;
3795 }
3796 /* FALLTHROUGH */
3797 case ERROR_FILE_NOT_FOUND:
3798 case ERROR_BAD_NETPATH:
3799 errno = ENOENT;
3800 break;
3801 default:
3802 errno = EACCES;
3803 break;
3804 }
3805 return -1;
3806 }
3807 if ((mode & X_OK) != 0
3808 && !(is_exec (path) || (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0))
3809 {
3810 errno = EACCES;
3811 return -1;
3812 }
3813 if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0)
3814 {
3815 errno = EACCES;
3816 return -1;
3817 }
3818 if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
3819 {
3820 errno = EACCES;
3821 return -1;
3822 }
3823 return 0;
3824 }
3825
3826 /* A version of 'access' to be used locally with file names in
3827 locale-specific encoding. Does not resolve symlinks and does not
3828 support file names on FAT12 and FAT16 volumes, but that's OK, since
3829 we only invoke this function for files inside the Emacs source or
3830 installation tree, on directories (so any symlinks should have the
3831 directory bit set), and on short file names such as "C:/.emacs". */
3832 static int
3833 sys_access (const char *fname, int mode)
3834 {
3835 char fname_copy[MAX_PATH], *p;
3836 DWORD attributes;
3837
3838 strcpy (fname_copy, fname);
3839 /* Do the equivalent of unixtodos_filename. */
3840 for (p = fname_copy; *p; p = CharNext (p))
3841 if (*p == '/')
3842 *p = '\\';
3843
3844 if ((attributes = GetFileAttributesA (fname_copy)) == -1)
3845 {
3846 DWORD w32err = GetLastError ();
3847
3848 switch (w32err)
3849 {
3850 case ERROR_INVALID_NAME:
3851 case ERROR_BAD_PATHNAME:
3852 case ERROR_FILE_NOT_FOUND:
3853 case ERROR_BAD_NETPATH:
3854 errno = ENOENT;
3855 break;
3856 default:
3857 errno = EACCES;
3858 break;
3859 }
3860 return -1;
3861 }
3862 if ((mode & X_OK) != 0
3863 && !(is_exec (fname_copy)
3864 || (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0))
3865 {
3866 errno = EACCES;
3867 return -1;
3868 }
3869 if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0)
3870 {
3871 errno = EACCES;
3872 return -1;
3873 }
3874 if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
3875 {
3876 errno = EACCES;
3877 return -1;
3878 }
3879 return 0;
3880 }
3881
3882 /* Shadow some MSVC runtime functions to map requests for long filenames
3883 to reasonable short names if necessary. This was originally added to
3884 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
3885 long file names. */
3886
3887 int
3888 sys_chdir (const char * path)
3889 {
3890 path = map_w32_filename (path, NULL);
3891 if (w32_unicode_filenames)
3892 {
3893 wchar_t newdir_w[MAX_PATH];
3894
3895 if (filename_to_utf16 (path, newdir_w) == 0)
3896 return _wchdir (newdir_w);
3897 return -1;
3898 }
3899 else
3900 {
3901 char newdir_a[MAX_PATH];
3902
3903 if (filename_to_ansi (path, newdir_a) == 0)
3904 return _chdir (newdir_a);
3905 return -1;
3906 }
3907 }
3908
3909 int
3910 sys_chmod (const char * path, int mode)
3911 {
3912 path = chase_symlinks (map_w32_filename (path, NULL));
3913 if (w32_unicode_filenames)
3914 {
3915 wchar_t path_w[MAX_PATH];
3916
3917 filename_to_utf16 (path, path_w);
3918 return _wchmod (path_w, mode);
3919 }
3920 else
3921 {
3922 char path_a[MAX_PATH];
3923
3924 filename_to_ansi (path, path_a);
3925 return _chmod (path_a, mode);
3926 }
3927 }
3928
3929 int
3930 sys_creat (const char * path, int mode)
3931 {
3932 path = map_w32_filename (path, NULL);
3933 if (w32_unicode_filenames)
3934 {
3935 wchar_t path_w[MAX_PATH];
3936
3937 filename_to_utf16 (path, path_w);
3938 return _wcreat (path_w, mode);
3939 }
3940 else
3941 {
3942 char path_a[MAX_PATH];
3943
3944 filename_to_ansi (path, path_a);
3945 return _creat (path_a, mode);
3946 }
3947 }
3948
3949 FILE *
3950 sys_fopen (const char * path, const char * mode)
3951 {
3952 int fd;
3953 int oflag;
3954 const char * mode_save = mode;
3955
3956 /* Force all file handles to be non-inheritable. This is necessary to
3957 ensure child processes don't unwittingly inherit handles that might
3958 prevent future file access. */
3959
3960 if (mode[0] == 'r')
3961 oflag = O_RDONLY;
3962 else if (mode[0] == 'w' || mode[0] == 'a')
3963 oflag = O_WRONLY | O_CREAT | O_TRUNC;
3964 else
3965 return NULL;
3966
3967 /* Only do simplistic option parsing. */
3968 while (*++mode)
3969 if (mode[0] == '+')
3970 {
3971 oflag &= ~(O_RDONLY | O_WRONLY);
3972 oflag |= O_RDWR;
3973 }
3974 else if (mode[0] == 'b')
3975 {
3976 oflag &= ~O_TEXT;
3977 oflag |= O_BINARY;
3978 }
3979 else if (mode[0] == 't')
3980 {
3981 oflag &= ~O_BINARY;
3982 oflag |= O_TEXT;
3983 }
3984 else break;
3985
3986 path = map_w32_filename (path, NULL);
3987 if (w32_unicode_filenames)
3988 {
3989 wchar_t path_w[MAX_PATH];
3990
3991 filename_to_utf16 (path, path_w);
3992 fd = _wopen (path_w, oflag | _O_NOINHERIT, 0644);
3993 }
3994 else
3995 {
3996 char path_a[MAX_PATH];
3997
3998 filename_to_ansi (path, path_a);
3999 fd = _open (path_a, oflag | _O_NOINHERIT, 0644);
4000 }
4001 if (fd < 0)
4002 return NULL;
4003
4004 return _fdopen (fd, mode_save);
4005 }
4006
4007 /* This only works on NTFS volumes, but is useful to have. */
4008 int
4009 sys_link (const char * old, const char * new)
4010 {
4011 HANDLE fileh;
4012 int result = -1;
4013 char oldname[MAX_UTF8_PATH], newname[MAX_UTF8_PATH];
4014 wchar_t oldname_w[MAX_PATH];
4015 char oldname_a[MAX_PATH];
4016
4017 if (old == NULL || new == NULL)
4018 {
4019 errno = ENOENT;
4020 return -1;
4021 }
4022
4023 strcpy (oldname, map_w32_filename (old, NULL));
4024 strcpy (newname, map_w32_filename (new, NULL));
4025
4026 if (w32_unicode_filenames)
4027 {
4028 filename_to_utf16 (oldname, oldname_w);
4029 fileh = CreateFileW (oldname_w, 0, 0, NULL, OPEN_EXISTING,
4030 FILE_FLAG_BACKUP_SEMANTICS, NULL);
4031 }
4032 else
4033 {
4034 filename_to_ansi (oldname, oldname_a);
4035 fileh = CreateFileA (oldname_a, 0, 0, NULL, OPEN_EXISTING,
4036 FILE_FLAG_BACKUP_SEMANTICS, NULL);
4037 }
4038 if (fileh != INVALID_HANDLE_VALUE)
4039 {
4040 int wlen;
4041
4042 /* Confusingly, the "alternate" stream name field does not apply
4043 when restoring a hard link, and instead contains the actual
4044 stream data for the link (ie. the name of the link to create).
4045 The WIN32_STREAM_ID structure before the cStreamName field is
4046 the stream header, which is then immediately followed by the
4047 stream data. */
4048
4049 struct {
4050 WIN32_STREAM_ID wid;
4051 WCHAR wbuffer[MAX_PATH]; /* extra space for link name */
4052 } data;
4053
4054 /* We used to pass MB_PRECOMPOSED as the 2nd arg here, but MSDN
4055 indicates that flag is unsupported for CP_UTF8, and OTOH says
4056 it is the default anyway. */
4057 wlen = pMultiByteToWideChar (CP_UTF8, 0, newname, -1,
4058 data.wid.cStreamName, MAX_PATH);
4059 if (wlen > 0)
4060 {
4061 LPVOID context = NULL;
4062 DWORD wbytes = 0;
4063
4064 data.wid.dwStreamId = BACKUP_LINK;
4065 data.wid.dwStreamAttributes = 0;
4066 data.wid.Size.LowPart = wlen * sizeof (WCHAR);
4067 data.wid.Size.HighPart = 0;
4068 data.wid.dwStreamNameSize = 0;
4069
4070 if (BackupWrite (fileh, (LPBYTE)&data,
4071 offsetof (WIN32_STREAM_ID, cStreamName)
4072 + data.wid.Size.LowPart,
4073 &wbytes, FALSE, FALSE, &context)
4074 && BackupWrite (fileh, NULL, 0, &wbytes, TRUE, FALSE, &context))
4075 {
4076 /* succeeded */
4077 result = 0;
4078 }
4079 else
4080 {
4081 DWORD err = GetLastError ();
4082 DWORD attributes;
4083
4084 switch (err)
4085 {
4086 case ERROR_ACCESS_DENIED:
4087 /* This is what happens when OLDNAME is a directory,
4088 since Windows doesn't support hard links to
4089 directories. Posix says to set errno to EPERM in
4090 that case. */
4091 if (w32_unicode_filenames)
4092 attributes = GetFileAttributesW (oldname_w);
4093 else
4094 attributes = GetFileAttributesA (oldname_a);
4095 if (attributes != -1
4096 && (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
4097 errno = EPERM;
4098 else if (attributes == -1
4099 && is_unc_volume (oldname)
4100 && unc_volume_file_attributes (oldname) != -1)
4101 errno = EPERM;
4102 else
4103 errno = EACCES;
4104 break;
4105 case ERROR_TOO_MANY_LINKS:
4106 errno = EMLINK;
4107 break;
4108 case ERROR_NOT_SAME_DEVICE:
4109 errno = EXDEV;
4110 break;
4111 default:
4112 errno = EINVAL;
4113 break;
4114 }
4115 }
4116 }
4117
4118 CloseHandle (fileh);
4119 }
4120 else
4121 errno = ENOENT;
4122
4123 return result;
4124 }
4125
4126 int
4127 sys_mkdir (const char * path)
4128 {
4129 path = map_w32_filename (path, NULL);
4130
4131 if (w32_unicode_filenames)
4132 {
4133 wchar_t path_w[MAX_PATH];
4134
4135 filename_to_utf16 (path, path_w);
4136 return _wmkdir (path_w);
4137 }
4138 else
4139 {
4140 char path_a[MAX_PATH];
4141
4142 filename_to_ansi (path, path_a);
4143 return _mkdir (path_a);
4144 }
4145 }
4146
4147 int
4148 sys_open (const char * path, int oflag, int mode)
4149 {
4150 const char* mpath = map_w32_filename (path, NULL);
4151 int res = -1;
4152
4153 if (w32_unicode_filenames)
4154 {
4155 wchar_t mpath_w[MAX_PATH];
4156
4157 filename_to_utf16 (mpath, mpath_w);
4158 /* If possible, try to open file without _O_CREAT, to be able to
4159 write to existing hidden and system files. Force all file
4160 handles to be non-inheritable. */
4161 if ((oflag & (_O_CREAT | _O_EXCL)) != (_O_CREAT | _O_EXCL))
4162 res = _wopen (mpath_w, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
4163 if (res < 0)
4164 res = _wopen (mpath_w, oflag | _O_NOINHERIT, mode);
4165 }
4166 else
4167 {
4168 char mpath_a[MAX_PATH];
4169
4170 filename_to_ansi (mpath, mpath_a);
4171 if ((oflag & (_O_CREAT | _O_EXCL)) != (_O_CREAT | _O_EXCL))
4172 res = _open (mpath_a, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
4173 if (res < 0)
4174 res = _open (mpath_a, oflag | _O_NOINHERIT, mode);
4175 }
4176
4177 return res;
4178 }
4179
4180 /* Implementation of mkostemp for MS-Windows, to avoid race conditions
4181 when using mktemp.
4182
4183 Standard algorithm for generating a temporary file name seems to be
4184 use pid or tid with a letter on the front (in place of the 6 X's)
4185 and cycle through the letters to find a unique name. We extend
4186 that to allow any reasonable character as the first of the 6 X's,
4187 so that the number of simultaneously used temporary files will be
4188 greater. */
4189
4190 int
4191 mkostemp (char * template, int flags)
4192 {
4193 char * p;
4194 int i, fd = -1;
4195 unsigned uid = GetCurrentThreadId ();
4196 int save_errno = errno;
4197 static char first_char[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
4198
4199 errno = EINVAL;
4200 if (template == NULL)
4201 return -1;
4202
4203 p = template + strlen (template);
4204 i = 5;
4205 /* replace up to the last 5 X's with uid in decimal */
4206 while (--p >= template && p[0] == 'X' && --i >= 0)
4207 {
4208 p[0] = '0' + uid % 10;
4209 uid /= 10;
4210 }
4211
4212 if (i < 0 && p[0] == 'X')
4213 {
4214 i = 0;
4215 do
4216 {
4217 p[0] = first_char[i];
4218 if ((fd = sys_open (template,
4219 flags | _O_CREAT | _O_EXCL | _O_RDWR,
4220 S_IRUSR | S_IWUSR)) >= 0
4221 || errno != EEXIST)
4222 {
4223 if (fd >= 0)
4224 errno = save_errno;
4225 return fd;
4226 }
4227 }
4228 while (++i < sizeof (first_char));
4229 }
4230
4231 /* Template is badly formed or else we can't generate a unique name. */
4232 return -1;
4233 }
4234
4235 int
4236 fchmod (int fd, mode_t mode)
4237 {
4238 return 0;
4239 }
4240
4241 int
4242 sys_rename_replace (const char *oldname, const char *newname, BOOL force)
4243 {
4244 BOOL result;
4245 char temp[MAX_UTF8_PATH], temp_a[MAX_PATH];;
4246 int newname_dev;
4247 int oldname_dev;
4248 bool have_temp_a = false;
4249
4250 /* MoveFile on Windows 95 doesn't correctly change the short file name
4251 alias in a number of circumstances (it is not easy to predict when
4252 just by looking at oldname and newname, unfortunately). In these
4253 cases, renaming through a temporary name avoids the problem.
4254
4255 A second problem on Windows 95 is that renaming through a temp name when
4256 newname is uppercase fails (the final long name ends up in
4257 lowercase, although the short alias might be uppercase) UNLESS the
4258 long temp name is not 8.3.
4259
4260 So, on Windows 95 we always rename through a temp name, and we make sure
4261 the temp name has a long extension to ensure correct renaming. */
4262
4263 strcpy (temp, map_w32_filename (oldname, NULL));
4264
4265 /* volume_info is set indirectly by map_w32_filename. */
4266 oldname_dev = volume_info.serialnum;
4267
4268 if (os_subtype == OS_9X)
4269 {
4270 char * o;
4271 char * p;
4272 int i = 0;
4273 char oldname_a[MAX_PATH];
4274
4275 oldname = map_w32_filename (oldname, NULL);
4276 filename_to_ansi (oldname, oldname_a);
4277 filename_to_ansi (temp, temp_a);
4278 if ((o = strrchr (oldname_a, '\\')))
4279 o++;
4280 else
4281 o = (char *) oldname_a;
4282
4283 if ((p = strrchr (temp_a, '\\')))
4284 p++;
4285 else
4286 p = temp_a;
4287
4288 do
4289 {
4290 /* Force temp name to require a manufactured 8.3 alias - this
4291 seems to make the second rename work properly. */
4292 sprintf (p, "_.%s.%u", o, i);
4293 i++;
4294 result = rename (oldname_a, temp_a);
4295 }
4296 /* This loop must surely terminate! */
4297 while (result < 0 && errno == EEXIST);
4298 if (result < 0)
4299 return -1;
4300 have_temp_a = true;
4301 }
4302
4303 /* If FORCE, emulate Unix behavior - newname is deleted if it already exists
4304 (at least if it is a file; don't do this for directories).
4305
4306 Since we mustn't do this if we are just changing the case of the
4307 file name (we would end up deleting the file we are trying to
4308 rename!), we let rename detect if the destination file already
4309 exists - that way we avoid the possible pitfalls of trying to
4310 determine ourselves whether two names really refer to the same
4311 file, which is not always possible in the general case. (Consider
4312 all the permutations of shared or subst'd drives, etc.) */
4313
4314 newname = map_w32_filename (newname, NULL);
4315
4316 /* volume_info is set indirectly by map_w32_filename. */
4317 newname_dev = volume_info.serialnum;
4318
4319 if (w32_unicode_filenames)
4320 {
4321 wchar_t temp_w[MAX_PATH], newname_w[MAX_PATH];
4322
4323 filename_to_utf16 (temp, temp_w);
4324 filename_to_utf16 (newname, newname_w);
4325 result = _wrename (temp_w, newname_w);
4326 if (result < 0 && force)
4327 {
4328 DWORD w32err = GetLastError ();
4329
4330 if (errno == EACCES
4331 && newname_dev != oldname_dev)
4332 {
4333 /* The implementation of `rename' on Windows does not return
4334 errno = EXDEV when you are moving a directory to a
4335 different storage device (ex. logical disk). It returns
4336 EACCES instead. So here we handle such situations and
4337 return EXDEV. */
4338 DWORD attributes;
4339
4340 if ((attributes = GetFileAttributesW (temp_w)) != -1
4341 && (attributes & FILE_ATTRIBUTE_DIRECTORY))
4342 errno = EXDEV;
4343 }
4344 else if (errno == EEXIST)
4345 {
4346 if (_wchmod (newname_w, 0666) != 0)
4347 return result;
4348 if (_wunlink (newname_w) != 0)
4349 return result;
4350 result = _wrename (temp_w, newname_w);
4351 }
4352 else if (w32err == ERROR_PRIVILEGE_NOT_HELD
4353 && is_symlink (temp))
4354 {
4355 /* This is Windows prohibiting the user from creating a
4356 symlink in another place, since that requires
4357 privileges. */
4358 errno = EPERM;
4359 }
4360 }
4361 }
4362 else
4363 {
4364 char newname_a[MAX_PATH];
4365
4366 if (!have_temp_a)
4367 filename_to_ansi (temp, temp_a);
4368 filename_to_ansi (newname, newname_a);
4369 result = rename (temp_a, newname_a);
4370 if (result < 0 && force)
4371 {
4372 DWORD w32err = GetLastError ();
4373
4374 if (errno == EACCES
4375 && newname_dev != oldname_dev)
4376 {
4377 DWORD attributes;
4378
4379 if ((attributes = GetFileAttributesA (temp_a)) != -1
4380 && (attributes & FILE_ATTRIBUTE_DIRECTORY))
4381 errno = EXDEV;
4382 }
4383 else if (errno == EEXIST)
4384 {
4385 if (_chmod (newname_a, 0666) != 0)
4386 return result;
4387 if (_unlink (newname_a) != 0)
4388 return result;
4389 result = rename (temp_a, newname_a);
4390 }
4391 else if (w32err == ERROR_PRIVILEGE_NOT_HELD
4392 && is_symlink (temp))
4393 errno = EPERM;
4394 }
4395 }
4396
4397 return result;
4398 }
4399
4400 int
4401 sys_rename (char const *old, char const *new)
4402 {
4403 return sys_rename_replace (old, new, TRUE);
4404 }
4405
4406 int
4407 sys_rmdir (const char * path)
4408 {
4409 path = map_w32_filename (path, NULL);
4410
4411 if (w32_unicode_filenames)
4412 {
4413 wchar_t path_w[MAX_PATH];
4414
4415 filename_to_utf16 (path, path_w);
4416 return _wrmdir (path_w);
4417 }
4418 else
4419 {
4420 char path_a[MAX_PATH];
4421
4422 filename_to_ansi (path, path_a);
4423 return _rmdir (path_a);
4424 }
4425 }
4426
4427 int
4428 sys_unlink (const char * path)
4429 {
4430 path = map_w32_filename (path, NULL);
4431
4432 if (w32_unicode_filenames)
4433 {
4434 wchar_t path_w[MAX_PATH];
4435
4436 filename_to_utf16 (path, path_w);
4437 /* On Unix, unlink works without write permission. */
4438 _wchmod (path_w, 0666);
4439 return _wunlink (path_w);
4440 }
4441 else
4442 {
4443 char path_a[MAX_PATH];
4444
4445 filename_to_ansi (path, path_a);
4446 _chmod (path_a, 0666);
4447 return _unlink (path_a);
4448 }
4449 }
4450
4451 static FILETIME utc_base_ft;
4452 static ULONGLONG utc_base; /* In 100ns units */
4453 static int init = 0;
4454
4455 #define FILETIME_TO_U64(result, ft) \
4456 do { \
4457 ULARGE_INTEGER uiTemp; \
4458 uiTemp.LowPart = (ft).dwLowDateTime; \
4459 uiTemp.HighPart = (ft).dwHighDateTime; \
4460 result = uiTemp.QuadPart; \
4461 } while (0)
4462
4463 static void
4464 initialize_utc_base (void)
4465 {
4466 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
4467 SYSTEMTIME st;
4468
4469 st.wYear = 1970;
4470 st.wMonth = 1;
4471 st.wDay = 1;
4472 st.wHour = 0;
4473 st.wMinute = 0;
4474 st.wSecond = 0;
4475 st.wMilliseconds = 0;
4476
4477 SystemTimeToFileTime (&st, &utc_base_ft);
4478 FILETIME_TO_U64 (utc_base, utc_base_ft);
4479 }
4480
4481 static time_t
4482 convert_time (FILETIME ft)
4483 {
4484 ULONGLONG tmp;
4485
4486 if (!init)
4487 {
4488 initialize_utc_base ();
4489 init = 1;
4490 }
4491
4492 if (CompareFileTime (&ft, &utc_base_ft) < 0)
4493 return 0;
4494
4495 FILETIME_TO_U64 (tmp, ft);
4496 return (time_t) ((tmp - utc_base) / 10000000L);
4497 }
4498
4499 static void
4500 convert_from_time_t (time_t time, FILETIME * pft)
4501 {
4502 ULARGE_INTEGER tmp;
4503
4504 if (!init)
4505 {
4506 initialize_utc_base ();
4507 init = 1;
4508 }
4509
4510 /* time in 100ns units since 1-Jan-1601 */
4511 tmp.QuadPart = (ULONGLONG) time * 10000000L + utc_base;
4512 pft->dwHighDateTime = tmp.HighPart;
4513 pft->dwLowDateTime = tmp.LowPart;
4514 }
4515
4516 static PSECURITY_DESCRIPTOR
4517 get_file_security_desc_by_handle (HANDLE h)
4518 {
4519 PSECURITY_DESCRIPTOR psd = NULL;
4520 DWORD err;
4521 SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION
4522 | GROUP_SECURITY_INFORMATION /* | DACL_SECURITY_INFORMATION */ ;
4523
4524 err = get_security_info (h, SE_FILE_OBJECT, si,
4525 NULL, NULL, NULL, NULL, &psd);
4526 if (err != ERROR_SUCCESS)
4527 return NULL;
4528
4529 return psd;
4530 }
4531
4532 static PSECURITY_DESCRIPTOR
4533 get_file_security_desc_by_name (const char *fname)
4534 {
4535 PSECURITY_DESCRIPTOR psd = NULL;
4536 DWORD sd_len, err;
4537 SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION
4538 | GROUP_SECURITY_INFORMATION /* | DACL_SECURITY_INFORMATION */ ;
4539
4540 if (!get_file_security (fname, si, psd, 0, &sd_len))
4541 {
4542 err = GetLastError ();
4543 if (err != ERROR_INSUFFICIENT_BUFFER)
4544 return NULL;
4545 }
4546
4547 psd = xmalloc (sd_len);
4548 if (!get_file_security (fname, si, psd, sd_len, &sd_len))
4549 {
4550 xfree (psd);
4551 return NULL;
4552 }
4553
4554 return psd;
4555 }
4556
4557 static DWORD
4558 get_rid (PSID sid)
4559 {
4560 unsigned n_subauthorities;
4561
4562 /* Use the last sub-authority value of the RID, the relative
4563 portion of the SID, as user/group ID. */
4564 n_subauthorities = *get_sid_sub_authority_count (sid);
4565 if (n_subauthorities < 1)
4566 return 0; /* the "World" RID */
4567 return *get_sid_sub_authority (sid, n_subauthorities - 1);
4568 }
4569
4570 /* Caching SID and account values for faster lokup. */
4571
4572 struct w32_id {
4573 unsigned rid;
4574 struct w32_id *next;
4575 char name[GNLEN+1];
4576 unsigned char sid[FLEXIBLE_ARRAY_MEMBER];
4577 };
4578
4579 static struct w32_id *w32_idlist;
4580
4581 static int
4582 w32_cached_id (PSID sid, unsigned *id, char *name)
4583 {
4584 struct w32_id *tail, *found;
4585
4586 for (found = NULL, tail = w32_idlist; tail; tail = tail->next)
4587 {
4588 if (equal_sid ((PSID)tail->sid, sid))
4589 {
4590 found = tail;
4591 break;
4592 }
4593 }
4594 if (found)
4595 {
4596 *id = found->rid;
4597 strcpy (name, found->name);
4598 return 1;
4599 }
4600 else
4601 return 0;
4602 }
4603
4604 static void
4605 w32_add_to_cache (PSID sid, unsigned id, char *name)
4606 {
4607 DWORD sid_len;
4608 struct w32_id *new_entry;
4609
4610 /* We don't want to leave behind stale cache from when Emacs was
4611 dumped. */
4612 if (initialized)
4613 {
4614 sid_len = get_length_sid (sid);
4615 new_entry = xmalloc (offsetof (struct w32_id, sid) + sid_len);
4616 if (new_entry)
4617 {
4618 new_entry->rid = id;
4619 strcpy (new_entry->name, name);
4620 copy_sid (sid_len, (PSID)new_entry->sid, sid);
4621 new_entry->next = w32_idlist;
4622 w32_idlist = new_entry;
4623 }
4624 }
4625 }
4626
4627 #define UID 1
4628 #define GID 2
4629
4630 static int
4631 get_name_and_id (PSECURITY_DESCRIPTOR psd, unsigned *id, char *nm, int what)
4632 {
4633 PSID sid = NULL;
4634 BOOL dflt;
4635 SID_NAME_USE ignore;
4636 char name[UNLEN+1];
4637 DWORD name_len = sizeof (name);
4638 char domain[1024];
4639 DWORD domain_len = sizeof (domain);
4640 int use_dflt = 0;
4641 int result;
4642
4643 if (what == UID)
4644 result = get_security_descriptor_owner (psd, &sid, &dflt);
4645 else if (what == GID)
4646 result = get_security_descriptor_group (psd, &sid, &dflt);
4647 else
4648 result = 0;
4649
4650 if (!result || !is_valid_sid (sid))
4651 use_dflt = 1;
4652 else if (!w32_cached_id (sid, id, nm))
4653 {
4654 if (!lookup_account_sid (NULL, sid, name, &name_len,
4655 domain, &domain_len, &ignore)
4656 || name_len > UNLEN+1)
4657 use_dflt = 1;
4658 else
4659 {
4660 *id = get_rid (sid);
4661 strcpy (nm, name);
4662 w32_add_to_cache (sid, *id, name);
4663 }
4664 }
4665 return use_dflt;
4666 }
4667
4668 static void
4669 get_file_owner_and_group (PSECURITY_DESCRIPTOR psd, struct stat *st)
4670 {
4671 int dflt_usr = 0, dflt_grp = 0;
4672
4673 if (!psd)
4674 {
4675 dflt_usr = 1;
4676 dflt_grp = 1;
4677 }
4678 else
4679 {
4680 if (get_name_and_id (psd, &st->st_uid, st->st_uname, UID))
4681 dflt_usr = 1;
4682 if (get_name_and_id (psd, &st->st_gid, st->st_gname, GID))
4683 dflt_grp = 1;
4684 }
4685 /* Consider files to belong to current user/group, if we cannot get
4686 more accurate information. */
4687 if (dflt_usr)
4688 {
4689 st->st_uid = dflt_passwd.pw_uid;
4690 strcpy (st->st_uname, dflt_passwd.pw_name);
4691 }
4692 if (dflt_grp)
4693 {
4694 st->st_gid = dflt_passwd.pw_gid;
4695 strcpy (st->st_gname, dflt_group.gr_name);
4696 }
4697 }
4698
4699 /* Return non-zero if NAME is a potentially slow filesystem. */
4700 int
4701 is_slow_fs (const char *name)
4702 {
4703 char drive_root[4];
4704 UINT devtype;
4705
4706 if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
4707 devtype = DRIVE_REMOTE; /* assume UNC name is remote */
4708 else if (!(strlen (name) >= 2 && IS_DEVICE_SEP (name[1])))
4709 devtype = GetDriveType (NULL); /* use root of current drive */
4710 else
4711 {
4712 /* GetDriveType needs the root directory of the drive. */
4713 strncpy (drive_root, name, 2);
4714 drive_root[2] = '\\';
4715 drive_root[3] = '\0';
4716 devtype = GetDriveType (drive_root);
4717 }
4718 return !(devtype == DRIVE_FIXED || devtype == DRIVE_RAMDISK);
4719 }
4720
4721 /* If this is non-zero, the caller wants accurate information about
4722 file's owner and group, which could be expensive to get. dired.c
4723 uses this flag when needed for the job at hand. */
4724 int w32_stat_get_owner_group;
4725
4726 /* MSVC stat function can't cope with UNC names and has other bugs, so
4727 replace it with our own. This also allows us to calculate consistent
4728 inode values and owner/group without hacks in the main Emacs code,
4729 and support file names encoded in UTF-8. */
4730
4731 static int
4732 stat_worker (const char * path, struct stat * buf, int follow_symlinks)
4733 {
4734 char *name, *save_name, *r;
4735 WIN32_FIND_DATAW wfd_w;
4736 WIN32_FIND_DATAA wfd_a;
4737 HANDLE fh;
4738 unsigned __int64 fake_inode = 0;
4739 int permission;
4740 int len;
4741 int rootdir = FALSE;
4742 PSECURITY_DESCRIPTOR psd = NULL;
4743 int is_a_symlink = 0;
4744 DWORD file_flags = FILE_FLAG_BACKUP_SEMANTICS;
4745 DWORD access_rights = 0;
4746 DWORD fattrs = 0, serialnum = 0, fs_high = 0, fs_low = 0, nlinks = 1;
4747 FILETIME ctime, atime, wtime;
4748 wchar_t name_w[MAX_PATH];
4749 char name_a[MAX_PATH];
4750
4751 if (path == NULL || buf == NULL)
4752 {
4753 errno = EFAULT;
4754 return -1;
4755 }
4756
4757 save_name = name = (char *) map_w32_filename (path, &path);
4758 /* Must be valid filename, no wild cards or other invalid
4759 characters. */
4760 if (strpbrk (name, "*?|<>\""))
4761 {
4762 errno = ENOENT;
4763 return -1;
4764 }
4765
4766 len = strlen (name);
4767 /* Allocate 1 extra byte so that we could append a slash to a root
4768 directory, down below. */
4769 name = strcpy (alloca (len + 2), name);
4770
4771 /* Avoid a somewhat costly call to is_symlink if the filesystem
4772 doesn't support symlinks. */
4773 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
4774 is_a_symlink = is_symlink (name);
4775
4776 /* Plan A: Open the file and get all the necessary information via
4777 the resulting handle. This solves several issues in one blow:
4778
4779 . retrieves attributes for the target of a symlink, if needed
4780 . gets attributes of root directories and symlinks pointing to
4781 root directories, thus avoiding the need for special-casing
4782 these and detecting them by examining the file-name format
4783 . retrieves more accurate attributes (e.g., non-zero size for
4784 some directories, esp. directories that are junction points)
4785 . correctly resolves "c:/..", "/.." and similar file names
4786 . avoids run-time penalties for 99% of use cases
4787
4788 Plan A is always tried first, unless the user asked not to (but
4789 if the file is a symlink and we need to follow links, we try Plan
4790 A even if the user asked not to).
4791
4792 If Plan A fails, we go to Plan B (below), where various
4793 potentially expensive techniques must be used to handle "special"
4794 files such as UNC volumes etc. */
4795 if (!(NILP (Vw32_get_true_file_attributes)
4796 || (EQ (Vw32_get_true_file_attributes, Qlocal) && is_slow_fs (name)))
4797 /* Following symlinks requires getting the info by handle. */
4798 || (is_a_symlink && follow_symlinks))
4799 {
4800 BY_HANDLE_FILE_INFORMATION info;
4801
4802 if (is_a_symlink && !follow_symlinks)
4803 file_flags |= FILE_FLAG_OPEN_REPARSE_POINT;
4804 /* READ_CONTROL access rights are required to get security info
4805 by handle. But if the OS doesn't support security in the
4806 first place, we don't need to try. */
4807 if (is_windows_9x () != TRUE)
4808 access_rights |= READ_CONTROL;
4809
4810 if (w32_unicode_filenames)
4811 {
4812 filename_to_utf16 (name, name_w);
4813 fh = CreateFileW (name_w, access_rights, 0, NULL, OPEN_EXISTING,
4814 file_flags, NULL);
4815 /* If CreateFile fails with READ_CONTROL, try again with
4816 zero as access rights. */
4817 if (fh == INVALID_HANDLE_VALUE && access_rights)
4818 fh = CreateFileW (name_w, 0, 0, NULL, OPEN_EXISTING,
4819 file_flags, NULL);
4820 }
4821 else
4822 {
4823 filename_to_ansi (name, name_a);
4824 fh = CreateFileA (name_a, access_rights, 0, NULL, OPEN_EXISTING,
4825 file_flags, NULL);
4826 if (fh == INVALID_HANDLE_VALUE && access_rights)
4827 fh = CreateFileA (name_a, 0, 0, NULL, OPEN_EXISTING,
4828 file_flags, NULL);
4829 }
4830 if (fh == INVALID_HANDLE_VALUE)
4831 goto no_true_file_attributes;
4832
4833 /* This is more accurate in terms of getting the correct number
4834 of links, but is quite slow (it is noticeable when Emacs is
4835 making a list of file name completions). */
4836 if (GetFileInformationByHandle (fh, &info))
4837 {
4838 nlinks = info.nNumberOfLinks;
4839 /* Might as well use file index to fake inode values, but this
4840 is not guaranteed to be unique unless we keep a handle open
4841 all the time (even then there are situations where it is
4842 not unique). Reputedly, there are at most 48 bits of info
4843 (on NTFS, presumably less on FAT). */
4844 fake_inode = info.nFileIndexHigh;
4845 fake_inode <<= 32;
4846 fake_inode += info.nFileIndexLow;
4847 serialnum = info.dwVolumeSerialNumber;
4848 fs_high = info.nFileSizeHigh;
4849 fs_low = info.nFileSizeLow;
4850 ctime = info.ftCreationTime;
4851 atime = info.ftLastAccessTime;
4852 wtime = info.ftLastWriteTime;
4853 fattrs = info.dwFileAttributes;
4854 }
4855 else
4856 {
4857 /* We don't go to Plan B here, because it's not clear that
4858 it's a good idea. The only known use case where
4859 CreateFile succeeds, but GetFileInformationByHandle fails
4860 (with ERROR_INVALID_FUNCTION) is for character devices
4861 such as NUL, PRN, etc. For these, switching to Plan B is
4862 a net loss, because we lose the character device
4863 attribute returned by GetFileType below (FindFirstFile
4864 doesn't set that bit in the attributes), and the other
4865 fields don't make sense for character devices anyway.
4866 Emacs doesn't really care for non-file entities in the
4867 context of l?stat, so neither do we. */
4868
4869 /* w32err is assigned so one could put a breakpoint here and
4870 examine its value, when GetFileInformationByHandle
4871 fails. */
4872 DWORD w32err = GetLastError ();
4873
4874 switch (w32err)
4875 {
4876 case ERROR_FILE_NOT_FOUND: /* can this ever happen? */
4877 errno = ENOENT;
4878 return -1;
4879 }
4880 }
4881
4882 /* Test for a symlink before testing for a directory, since
4883 symlinks to directories have the directory bit set, but we
4884 don't want them to appear as directories. */
4885 if (is_a_symlink && !follow_symlinks)
4886 buf->st_mode = S_IFLNK;
4887 else if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
4888 buf->st_mode = S_IFDIR;
4889 else
4890 {
4891 DWORD ftype = GetFileType (fh);
4892
4893 switch (ftype)
4894 {
4895 case FILE_TYPE_DISK:
4896 buf->st_mode = S_IFREG;
4897 break;
4898 case FILE_TYPE_PIPE:
4899 buf->st_mode = S_IFIFO;
4900 break;
4901 case FILE_TYPE_CHAR:
4902 case FILE_TYPE_UNKNOWN:
4903 default:
4904 buf->st_mode = S_IFCHR;
4905 }
4906 }
4907 /* We produce the fallback owner and group data, based on the
4908 current user that runs Emacs, in the following cases:
4909
4910 . caller didn't request owner and group info
4911 . this is Windows 9X
4912 . getting security by handle failed, and we need to produce
4913 information for the target of a symlink (this is better
4914 than producing a potentially misleading info about the
4915 symlink itself)
4916
4917 If getting security by handle fails, and we don't need to
4918 resolve symlinks, we try getting security by name. */
4919 if (!w32_stat_get_owner_group || is_windows_9x () == TRUE)
4920 get_file_owner_and_group (NULL, buf);
4921 else
4922 {
4923 psd = get_file_security_desc_by_handle (fh);
4924 if (psd)
4925 {
4926 get_file_owner_and_group (psd, buf);
4927 LocalFree (psd);
4928 }
4929 else if (!(is_a_symlink && follow_symlinks))
4930 {
4931 psd = get_file_security_desc_by_name (name);
4932 get_file_owner_and_group (psd, buf);
4933 xfree (psd);
4934 }
4935 else
4936 get_file_owner_and_group (NULL, buf);
4937 }
4938 CloseHandle (fh);
4939 }
4940 else
4941 {
4942 no_true_file_attributes:
4943 /* Plan B: Either getting a handle on the file failed, or the
4944 caller explicitly asked us to not bother making this
4945 information more accurate.
4946
4947 Implementation note: In Plan B, we never bother to resolve
4948 symlinks, even if we got here because we tried Plan A and
4949 failed. That's because, even if the caller asked for extra
4950 precision by setting Vw32_get_true_file_attributes to t,
4951 resolving symlinks requires acquiring a file handle to the
4952 symlink, which we already know will fail. And if the user
4953 did not ask for extra precision, resolving symlinks will fly
4954 in the face of that request, since the user then wants the
4955 lightweight version of the code. */
4956 rootdir = (path >= save_name + len - 1
4957 && (IS_DIRECTORY_SEP (*path) || *path == 0));
4958
4959 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
4960 r = IS_DEVICE_SEP (name[1]) ? &name[2] : name;
4961 if (IS_DIRECTORY_SEP (r[0])
4962 && r[1] == '.' && r[2] == '.' && r[3] == '\0')
4963 r[1] = r[2] = '\0';
4964
4965 /* Note: If NAME is a symlink to the root of a UNC volume
4966 (i.e. "\\SERVER"), we will not detect that here, and we will
4967 return data about the symlink as result of FindFirst below.
4968 This is unfortunate, but that marginal use case does not
4969 justify a call to chase_symlinks which would impose a penalty
4970 on all the other use cases. (We get here for symlinks to
4971 roots of UNC volumes because CreateFile above fails for them,
4972 unlike with symlinks to root directories X:\ of drives.) */
4973 if (is_unc_volume (name))
4974 {
4975 fattrs = unc_volume_file_attributes (name);
4976 if (fattrs == -1)
4977 return -1;
4978
4979 ctime = atime = wtime = utc_base_ft;
4980 }
4981 else if (rootdir)
4982 {
4983 /* Make sure root directories end in a slash. */
4984 if (!IS_DIRECTORY_SEP (name[len-1]))
4985 strcpy (name + len, "\\");
4986 if (GetDriveType (name) < 2)
4987 {
4988 errno = ENOENT;
4989 return -1;
4990 }
4991
4992 fattrs = FILE_ATTRIBUTE_DIRECTORY;
4993 ctime = atime = wtime = utc_base_ft;
4994 }
4995 else
4996 {
4997 int have_wfd = -1;
4998
4999 /* Make sure non-root directories do NOT end in a slash,
5000 otherwise FindFirstFile might fail. */
5001 if (IS_DIRECTORY_SEP (name[len-1]))
5002 name[len - 1] = 0;
5003
5004 /* (This is hacky, but helps when doing file completions on
5005 network drives.) Optimize by using information available from
5006 active readdir if possible. */
5007 len = strlen (dir_pathname);
5008 if (IS_DIRECTORY_SEP (dir_pathname[len-1]))
5009 len--;
5010 if (dir_find_handle != INVALID_HANDLE_VALUE
5011 && last_dir_find_data != -1
5012 && !(is_a_symlink && follow_symlinks)
5013 /* The 2 file-name comparisons below support only ASCII
5014 characters, and will lose (compare not equal) when
5015 the file names include non-ASCII characters that are
5016 the same but for the case. However, doing this
5017 properly involves: (a) converting both file names to
5018 UTF-16, (b) lower-casing both names using CharLowerW,
5019 and (c) comparing the results; this would be quite a
5020 bit slower, whereas Plan B is for users who want
5021 lightweight albeit inaccurate version of 'stat'. */
5022 && c_strncasecmp (save_name, dir_pathname, len) == 0
5023 && IS_DIRECTORY_SEP (name[len])
5024 && xstrcasecmp (name + len + 1, dir_static.d_name) == 0)
5025 {
5026 have_wfd = last_dir_find_data;
5027 /* This was the last entry returned by readdir. */
5028 if (last_dir_find_data == DIR_FIND_DATA_W)
5029 wfd_w = dir_find_data_w;
5030 else
5031 wfd_a = dir_find_data_a;
5032 }
5033 else
5034 {
5035 logon_network_drive (name);
5036
5037 if (w32_unicode_filenames)
5038 {
5039 filename_to_utf16 (name, name_w);
5040 fh = FindFirstFileW (name_w, &wfd_w);
5041 have_wfd = DIR_FIND_DATA_W;
5042 }
5043 else
5044 {
5045 filename_to_ansi (name, name_a);
5046 /* If NAME includes characters not representable by
5047 the current ANSI codepage, filename_to_ansi
5048 usually replaces them with a '?'. We don't want
5049 to let FindFirstFileA interpret those as wildcards,
5050 and "succeed", returning us data from some random
5051 file in the same directory. */
5052 if (_mbspbrk (name_a, "?"))
5053 fh = INVALID_HANDLE_VALUE;
5054 else
5055 fh = FindFirstFileA (name_a, &wfd_a);
5056 have_wfd = DIR_FIND_DATA_A;
5057 }
5058 if (fh == INVALID_HANDLE_VALUE)
5059 {
5060 errno = ENOENT;
5061 return -1;
5062 }
5063 FindClose (fh);
5064 }
5065 /* Note: if NAME is a symlink, the information we get from
5066 FindFirstFile is for the symlink, not its target. */
5067 if (have_wfd == DIR_FIND_DATA_W)
5068 {
5069 fattrs = wfd_w.dwFileAttributes;
5070 ctime = wfd_w.ftCreationTime;
5071 atime = wfd_w.ftLastAccessTime;
5072 wtime = wfd_w.ftLastWriteTime;
5073 fs_high = wfd_w.nFileSizeHigh;
5074 fs_low = wfd_w.nFileSizeLow;
5075 }
5076 else
5077 {
5078 fattrs = wfd_a.dwFileAttributes;
5079 ctime = wfd_a.ftCreationTime;
5080 atime = wfd_a.ftLastAccessTime;
5081 wtime = wfd_a.ftLastWriteTime;
5082 fs_high = wfd_a.nFileSizeHigh;
5083 fs_low = wfd_a.nFileSizeLow;
5084 }
5085 fake_inode = 0;
5086 nlinks = 1;
5087 serialnum = volume_info.serialnum;
5088 }
5089 if (is_a_symlink && !follow_symlinks)
5090 buf->st_mode = S_IFLNK;
5091 else if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
5092 buf->st_mode = S_IFDIR;
5093 else
5094 buf->st_mode = S_IFREG;
5095
5096 get_file_owner_and_group (NULL, buf);
5097 }
5098
5099 buf->st_ino = fake_inode;
5100
5101 buf->st_dev = serialnum;
5102 buf->st_rdev = serialnum;
5103
5104 buf->st_size = fs_high;
5105 buf->st_size <<= 32;
5106 buf->st_size += fs_low;
5107 buf->st_nlink = nlinks;
5108
5109 /* Convert timestamps to Unix format. */
5110 buf->st_mtime = convert_time (wtime);
5111 buf->st_atime = convert_time (atime);
5112 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
5113 buf->st_ctime = convert_time (ctime);
5114 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
5115
5116 /* determine rwx permissions */
5117 if (is_a_symlink && !follow_symlinks)
5118 permission = S_IREAD | S_IWRITE | S_IEXEC; /* Posix expectations */
5119 else
5120 {
5121 if (fattrs & FILE_ATTRIBUTE_READONLY)
5122 permission = S_IREAD;
5123 else
5124 permission = S_IREAD | S_IWRITE;
5125
5126 if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
5127 permission |= S_IEXEC;
5128 else if (is_exec (name))
5129 permission |= S_IEXEC;
5130 }
5131
5132 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
5133
5134 return 0;
5135 }
5136
5137 int
5138 stat (const char * path, struct stat * buf)
5139 {
5140 return stat_worker (path, buf, 1);
5141 }
5142
5143 int
5144 lstat (const char * path, struct stat * buf)
5145 {
5146 return stat_worker (path, buf, 0);
5147 }
5148
5149 int
5150 fstatat (int fd, char const *name, struct stat *st, int flags)
5151 {
5152 /* Rely on a hack: an open directory is modeled as file descriptor 0.
5153 This is good enough for the current usage in Emacs, but is fragile.
5154
5155 FIXME: Add proper support for fdopendir, fstatat, readlinkat.
5156 Gnulib does this and can serve as a model. */
5157 char fullname[MAX_UTF8_PATH];
5158
5159 if (fd != AT_FDCWD)
5160 {
5161 char lastc = dir_pathname[strlen (dir_pathname) - 1];
5162
5163 if (_snprintf (fullname, sizeof fullname, "%s%s%s",
5164 dir_pathname, IS_DIRECTORY_SEP (lastc) ? "" : "/", name)
5165 < 0)
5166 {
5167 errno = ENAMETOOLONG;
5168 return -1;
5169 }
5170 name = fullname;
5171 }
5172
5173 return stat_worker (name, st, ! (flags & AT_SYMLINK_NOFOLLOW));
5174 }
5175
5176 /* Provide fstat and utime as well as stat for consistent handling of
5177 file timestamps. */
5178 int
5179 fstat (int desc, struct stat * buf)
5180 {
5181 HANDLE fh = (HANDLE) _get_osfhandle (desc);
5182 BY_HANDLE_FILE_INFORMATION info;
5183 unsigned __int64 fake_inode;
5184 int permission;
5185
5186 switch (GetFileType (fh) & ~FILE_TYPE_REMOTE)
5187 {
5188 case FILE_TYPE_DISK:
5189 buf->st_mode = S_IFREG;
5190 if (!GetFileInformationByHandle (fh, &info))
5191 {
5192 errno = EACCES;
5193 return -1;
5194 }
5195 break;
5196 case FILE_TYPE_PIPE:
5197 buf->st_mode = S_IFIFO;
5198 goto non_disk;
5199 case FILE_TYPE_CHAR:
5200 case FILE_TYPE_UNKNOWN:
5201 default:
5202 buf->st_mode = S_IFCHR;
5203 non_disk:
5204 memset (&info, 0, sizeof (info));
5205 info.dwFileAttributes = 0;
5206 info.ftCreationTime = utc_base_ft;
5207 info.ftLastAccessTime = utc_base_ft;
5208 info.ftLastWriteTime = utc_base_ft;
5209 }
5210
5211 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
5212 buf->st_mode = S_IFDIR;
5213
5214 buf->st_nlink = info.nNumberOfLinks;
5215 /* Might as well use file index to fake inode values, but this
5216 is not guaranteed to be unique unless we keep a handle open
5217 all the time (even then there are situations where it is
5218 not unique). Reputedly, there are at most 48 bits of info
5219 (on NTFS, presumably less on FAT). */
5220 fake_inode = info.nFileIndexHigh;
5221 fake_inode <<= 32;
5222 fake_inode += info.nFileIndexLow;
5223
5224 /* MSVC defines _ino_t to be short; other libc's might not. */
5225 if (sizeof (buf->st_ino) == 2)
5226 buf->st_ino = fake_inode ^ (fake_inode >> 16);
5227 else
5228 buf->st_ino = fake_inode;
5229
5230 /* If the caller so requested, get the true file owner and group.
5231 Otherwise, consider the file to belong to the current user. */
5232 if (!w32_stat_get_owner_group || is_windows_9x () == TRUE)
5233 get_file_owner_and_group (NULL, buf);
5234 else
5235 {
5236 PSECURITY_DESCRIPTOR psd = NULL;
5237
5238 psd = get_file_security_desc_by_handle (fh);
5239 if (psd)
5240 {
5241 get_file_owner_and_group (psd, buf);
5242 LocalFree (psd);
5243 }
5244 else
5245 get_file_owner_and_group (NULL, buf);
5246 }
5247
5248 buf->st_dev = info.dwVolumeSerialNumber;
5249 buf->st_rdev = info.dwVolumeSerialNumber;
5250
5251 buf->st_size = info.nFileSizeHigh;
5252 buf->st_size <<= 32;
5253 buf->st_size += info.nFileSizeLow;
5254
5255 /* Convert timestamps to Unix format. */
5256 buf->st_mtime = convert_time (info.ftLastWriteTime);
5257 buf->st_atime = convert_time (info.ftLastAccessTime);
5258 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
5259 buf->st_ctime = convert_time (info.ftCreationTime);
5260 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
5261
5262 /* determine rwx permissions */
5263 if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
5264 permission = S_IREAD;
5265 else
5266 permission = S_IREAD | S_IWRITE;
5267
5268 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
5269 permission |= S_IEXEC;
5270 else
5271 {
5272 #if 0 /* no way of knowing the filename */
5273 char * p = strrchr (name, '.');
5274 if (p != NULL &&
5275 (xstrcasecmp (p, ".exe") == 0 ||
5276 xstrcasecmp (p, ".com") == 0 ||
5277 xstrcasecmp (p, ".bat") == 0 ||
5278 xstrcasecmp (p, ".cmd") == 0))
5279 permission |= S_IEXEC;
5280 #endif
5281 }
5282
5283 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
5284
5285 return 0;
5286 }
5287
5288 /* A version of 'utime' which handles directories as well as
5289 files. */
5290
5291 int
5292 utime (const char *name, struct utimbuf *times)
5293 {
5294 struct utimbuf deftime;
5295 HANDLE fh;
5296 FILETIME mtime;
5297 FILETIME atime;
5298
5299 if (times == NULL)
5300 {
5301 deftime.modtime = deftime.actime = time (NULL);
5302 times = &deftime;
5303 }
5304
5305 if (w32_unicode_filenames)
5306 {
5307 wchar_t name_utf16[MAX_PATH];
5308
5309 if (filename_to_utf16 (name, name_utf16) != 0)
5310 return -1; /* errno set by filename_to_utf16 */
5311
5312 /* Need write access to set times. */
5313 fh = CreateFileW (name_utf16, FILE_WRITE_ATTRIBUTES,
5314 /* If NAME specifies a directory, FILE_SHARE_DELETE
5315 allows other processes to delete files inside it,
5316 while we have the directory open. */
5317 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
5318 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
5319 }
5320 else
5321 {
5322 char name_ansi[MAX_PATH];
5323
5324 if (filename_to_ansi (name, name_ansi) != 0)
5325 return -1; /* errno set by filename_to_ansi */
5326
5327 fh = CreateFileA (name_ansi, FILE_WRITE_ATTRIBUTES,
5328 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
5329 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
5330 }
5331 if (fh != INVALID_HANDLE_VALUE)
5332 {
5333 convert_from_time_t (times->actime, &atime);
5334 convert_from_time_t (times->modtime, &mtime);
5335 if (!SetFileTime (fh, NULL, &atime, &mtime))
5336 {
5337 CloseHandle (fh);
5338 errno = EACCES;
5339 return -1;
5340 }
5341 CloseHandle (fh);
5342 }
5343 else
5344 {
5345 DWORD err = GetLastError ();
5346
5347 switch (err)
5348 {
5349 case ERROR_FILE_NOT_FOUND:
5350 case ERROR_PATH_NOT_FOUND:
5351 case ERROR_INVALID_DRIVE:
5352 case ERROR_BAD_NETPATH:
5353 case ERROR_DEV_NOT_EXIST:
5354 /* ERROR_INVALID_NAME is the error CreateFile sets when the
5355 file name includes ?s, i.e. translation to ANSI failed. */
5356 case ERROR_INVALID_NAME:
5357 errno = ENOENT;
5358 break;
5359 case ERROR_TOO_MANY_OPEN_FILES:
5360 errno = ENFILE;
5361 break;
5362 case ERROR_ACCESS_DENIED:
5363 case ERROR_SHARING_VIOLATION:
5364 errno = EACCES;
5365 break;
5366 default:
5367 errno = EINVAL;
5368 break;
5369 }
5370 return -1;
5371 }
5372 return 0;
5373 }
5374
5375 int
5376 sys_umask (int mode)
5377 {
5378 static int current_mask;
5379 int retval, arg = 0;
5380
5381 /* The only bit we really support is the write bit. Files are
5382 always readable on MS-Windows, and the execute bit does not exist
5383 at all. */
5384 /* FIXME: if the GROUP and OTHER bits are reset, we should use ACLs
5385 to prevent access by other users on NTFS. */
5386 if ((mode & S_IWRITE) != 0)
5387 arg |= S_IWRITE;
5388
5389 retval = _umask (arg);
5390 /* Merge into the return value the bits they've set the last time,
5391 which msvcrt.dll ignores and never returns. Emacs insists on its
5392 notion of mask being identical to what we return. */
5393 retval |= (current_mask & ~S_IWRITE);
5394 current_mask = mode;
5395
5396 return retval;
5397 }
5398
5399 \f
5400 /* Symlink-related functions. */
5401 #ifndef SYMBOLIC_LINK_FLAG_DIRECTORY
5402 #define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1
5403 #endif
5404
5405 int
5406 symlink (char const *filename, char const *linkname)
5407 {
5408 char linkfn[MAX_UTF8_PATH], *tgtfn;
5409 DWORD flags = 0;
5410 int dir_access, filename_ends_in_slash;
5411
5412 /* Diagnostics follows Posix as much as possible. */
5413 if (filename == NULL || linkname == NULL)
5414 {
5415 errno = EFAULT;
5416 return -1;
5417 }
5418 if (!*filename)
5419 {
5420 errno = ENOENT;
5421 return -1;
5422 }
5423 if (strlen (filename) > MAX_UTF8_PATH || strlen (linkname) > MAX_UTF8_PATH)
5424 {
5425 errno = ENAMETOOLONG;
5426 return -1;
5427 }
5428
5429 strcpy (linkfn, map_w32_filename (linkname, NULL));
5430 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) == 0)
5431 {
5432 errno = EPERM;
5433 return -1;
5434 }
5435
5436 /* Note: since empty FILENAME was already rejected, we can safely
5437 refer to FILENAME[1]. */
5438 if (!(IS_DIRECTORY_SEP (filename[0]) || IS_DEVICE_SEP (filename[1])))
5439 {
5440 /* Non-absolute FILENAME is understood as being relative to
5441 LINKNAME's directory. We need to prepend that directory to
5442 FILENAME to get correct results from faccessat below, since
5443 otherwise it will interpret FILENAME relative to the
5444 directory where the Emacs process runs. Note that
5445 make-symbolic-link always makes sure LINKNAME is a fully
5446 expanded file name. */
5447 char tem[MAX_UTF8_PATH];
5448 char *p = linkfn + strlen (linkfn);
5449
5450 while (p > linkfn && !IS_ANY_SEP (p[-1]))
5451 p--;
5452 if (p > linkfn)
5453 strncpy (tem, linkfn, p - linkfn);
5454 strcpy (tem + (p - linkfn), filename);
5455 dir_access = faccessat (AT_FDCWD, tem, D_OK, AT_EACCESS);
5456 }
5457 else
5458 dir_access = faccessat (AT_FDCWD, filename, D_OK, AT_EACCESS);
5459
5460 /* Since Windows distinguishes between symlinks to directories and
5461 to files, we provide a kludgy feature: if FILENAME doesn't
5462 exist, but ends in a slash, we create a symlink to directory. If
5463 FILENAME exists and is a directory, we always create a symlink to
5464 directory. */
5465 filename_ends_in_slash = IS_DIRECTORY_SEP (filename[strlen (filename) - 1]);
5466 if (dir_access == 0 || filename_ends_in_slash)
5467 flags = SYMBOLIC_LINK_FLAG_DIRECTORY;
5468
5469 tgtfn = (char *)map_w32_filename (filename, NULL);
5470 if (filename_ends_in_slash)
5471 tgtfn[strlen (tgtfn) - 1] = '\0';
5472
5473 errno = 0;
5474 if (!create_symbolic_link (linkfn, tgtfn, flags))
5475 {
5476 /* ENOSYS is set by create_symbolic_link, when it detects that
5477 the OS doesn't support the CreateSymbolicLink API. */
5478 if (errno != ENOSYS)
5479 {
5480 DWORD w32err = GetLastError ();
5481
5482 switch (w32err)
5483 {
5484 /* ERROR_SUCCESS is sometimes returned when LINKFN and
5485 TGTFN point to the same file name, go figure. */
5486 case ERROR_SUCCESS:
5487 case ERROR_FILE_EXISTS:
5488 errno = EEXIST;
5489 break;
5490 case ERROR_ACCESS_DENIED:
5491 errno = EACCES;
5492 break;
5493 case ERROR_FILE_NOT_FOUND:
5494 case ERROR_PATH_NOT_FOUND:
5495 case ERROR_BAD_NETPATH:
5496 case ERROR_INVALID_REPARSE_DATA:
5497 errno = ENOENT;
5498 break;
5499 case ERROR_DIRECTORY:
5500 errno = EISDIR;
5501 break;
5502 case ERROR_PRIVILEGE_NOT_HELD:
5503 case ERROR_NOT_ALL_ASSIGNED:
5504 errno = EPERM;
5505 break;
5506 case ERROR_DISK_FULL:
5507 errno = ENOSPC;
5508 break;
5509 default:
5510 errno = EINVAL;
5511 break;
5512 }
5513 }
5514 return -1;
5515 }
5516 return 0;
5517 }
5518
5519 /* A quick inexpensive test of whether FILENAME identifies a file that
5520 is a symlink. Returns non-zero if it is, zero otherwise. FILENAME
5521 must already be in the normalized form returned by
5522 map_w32_filename.
5523
5524 Note: for repeated operations on many files, it is best to test
5525 whether the underlying volume actually supports symlinks, by
5526 testing the FILE_SUPPORTS_REPARSE_POINTS bit in volume's flags, and
5527 avoid the call to this function if it doesn't. That's because the
5528 call to GetFileAttributes takes a non-negligible time, especially
5529 on non-local or removable filesystems. See stat_worker for an
5530 example of how to do that. */
5531 static int
5532 is_symlink (const char *filename)
5533 {
5534 DWORD attrs;
5535 wchar_t filename_w[MAX_PATH];
5536 char filename_a[MAX_PATH];
5537 WIN32_FIND_DATAW wfdw;
5538 WIN32_FIND_DATAA wfda;
5539 HANDLE fh;
5540 int attrs_mean_symlink;
5541
5542 if (w32_unicode_filenames)
5543 {
5544 filename_to_utf16 (filename, filename_w);
5545 attrs = GetFileAttributesW (filename_w);
5546 }
5547 else
5548 {
5549 filename_to_ansi (filename, filename_a);
5550 attrs = GetFileAttributesA (filename_a);
5551 }
5552 if (attrs == -1)
5553 {
5554 DWORD w32err = GetLastError ();
5555
5556 switch (w32err)
5557 {
5558 case ERROR_BAD_NETPATH: /* network share, can't be a symlink */
5559 break;
5560 case ERROR_ACCESS_DENIED:
5561 errno = EACCES;
5562 break;
5563 case ERROR_FILE_NOT_FOUND:
5564 case ERROR_PATH_NOT_FOUND:
5565 default:
5566 errno = ENOENT;
5567 break;
5568 }
5569 return 0;
5570 }
5571 if ((attrs & FILE_ATTRIBUTE_REPARSE_POINT) == 0)
5572 return 0;
5573 logon_network_drive (filename);
5574 if (w32_unicode_filenames)
5575 {
5576 fh = FindFirstFileW (filename_w, &wfdw);
5577 attrs_mean_symlink =
5578 (wfdw.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0
5579 && (wfdw.dwReserved0 & IO_REPARSE_TAG_SYMLINK) == IO_REPARSE_TAG_SYMLINK;
5580 }
5581 else if (_mbspbrk (filename_a, "?"))
5582 {
5583 /* filename_to_ansi failed to convert the file name. */
5584 errno = ENOENT;
5585 return 0;
5586 }
5587 else
5588 {
5589 fh = FindFirstFileA (filename_a, &wfda);
5590 attrs_mean_symlink =
5591 (wfda.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0
5592 && (wfda.dwReserved0 & IO_REPARSE_TAG_SYMLINK) == IO_REPARSE_TAG_SYMLINK;
5593 }
5594 if (fh == INVALID_HANDLE_VALUE)
5595 return 0;
5596 FindClose (fh);
5597 return attrs_mean_symlink;
5598 }
5599
5600 /* If NAME identifies a symbolic link, copy into BUF the file name of
5601 the symlink's target. Copy at most BUF_SIZE bytes, and do NOT
5602 null-terminate the target name, even if it fits. Return the number
5603 of bytes copied, or -1 if NAME is not a symlink or any error was
5604 encountered while resolving it. The file name copied into BUF is
5605 encoded in the current ANSI codepage. */
5606 ssize_t
5607 readlink (const char *name, char *buf, size_t buf_size)
5608 {
5609 const char *path;
5610 TOKEN_PRIVILEGES privs;
5611 int restore_privs = 0;
5612 HANDLE sh;
5613 ssize_t retval;
5614 char resolved[MAX_UTF8_PATH];
5615
5616 if (name == NULL)
5617 {
5618 errno = EFAULT;
5619 return -1;
5620 }
5621 if (!*name)
5622 {
5623 errno = ENOENT;
5624 return -1;
5625 }
5626
5627 path = map_w32_filename (name, NULL);
5628
5629 if (strlen (path) > MAX_UTF8_PATH)
5630 {
5631 errno = ENAMETOOLONG;
5632 return -1;
5633 }
5634
5635 errno = 0;
5636 if (is_windows_9x () == TRUE
5637 || (volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) == 0
5638 || !is_symlink (path))
5639 {
5640 if (!errno)
5641 errno = EINVAL; /* not a symlink */
5642 return -1;
5643 }
5644
5645 /* Done with simple tests, now we're in for some _real_ work. */
5646 if (enable_privilege (SE_BACKUP_NAME, TRUE, &privs))
5647 restore_privs = 1;
5648 /* Implementation note: From here and onward, don't return early,
5649 since that will fail to restore the original set of privileges of
5650 the calling thread. */
5651
5652 retval = -1; /* not too optimistic, are we? */
5653
5654 /* Note: In the next call to CreateFile, we use zero as the 2nd
5655 argument because, when the symlink is a hidden/system file,
5656 e.g. 'C:\Users\All Users', GENERIC_READ fails with
5657 ERROR_ACCESS_DENIED. Zero seems to work just fine, both for file
5658 and directory symlinks. */
5659 if (w32_unicode_filenames)
5660 {
5661 wchar_t path_w[MAX_PATH];
5662
5663 filename_to_utf16 (path, path_w);
5664 sh = CreateFileW (path_w, 0, 0, NULL, OPEN_EXISTING,
5665 FILE_FLAG_OPEN_REPARSE_POINT
5666 | FILE_FLAG_BACKUP_SEMANTICS,
5667 NULL);
5668 }
5669 else
5670 {
5671 char path_a[MAX_PATH];
5672
5673 filename_to_ansi (path, path_a);
5674 sh = CreateFileA (path_a, 0, 0, NULL, OPEN_EXISTING,
5675 FILE_FLAG_OPEN_REPARSE_POINT
5676 | FILE_FLAG_BACKUP_SEMANTICS,
5677 NULL);
5678 }
5679 if (sh != INVALID_HANDLE_VALUE)
5680 {
5681 BYTE reparse_buf[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
5682 REPARSE_DATA_BUFFER *reparse_data = (REPARSE_DATA_BUFFER *)&reparse_buf[0];
5683 DWORD retbytes;
5684
5685 if (!DeviceIoControl (sh, FSCTL_GET_REPARSE_POINT, NULL, 0,
5686 reparse_buf, MAXIMUM_REPARSE_DATA_BUFFER_SIZE,
5687 &retbytes, NULL))
5688 errno = EIO;
5689 else if (reparse_data->ReparseTag != IO_REPARSE_TAG_SYMLINK)
5690 errno = EINVAL;
5691 else
5692 {
5693 /* Copy the link target name, in wide characters, from
5694 reparse_data, then convert it to multibyte encoding in
5695 the current locale's codepage. */
5696 WCHAR *lwname;
5697 size_t lname_size;
5698 USHORT lwname_len =
5699 reparse_data->SymbolicLinkReparseBuffer.PrintNameLength;
5700 WCHAR *lwname_src =
5701 reparse_data->SymbolicLinkReparseBuffer.PathBuffer
5702 + reparse_data->SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(WCHAR);
5703 size_t size_to_copy = buf_size;
5704
5705 /* According to MSDN, PrintNameLength does not include the
5706 terminating null character. */
5707 lwname = alloca ((lwname_len + 1) * sizeof(WCHAR));
5708 memcpy (lwname, lwname_src, lwname_len);
5709 lwname[lwname_len/sizeof(WCHAR)] = 0; /* null-terminate */
5710 filename_from_utf16 (lwname, resolved);
5711 dostounix_filename (resolved);
5712 lname_size = strlen (resolved) + 1;
5713 if (lname_size <= buf_size)
5714 size_to_copy = lname_size;
5715 strncpy (buf, resolved, size_to_copy);
5716 /* Success! */
5717 retval = size_to_copy;
5718 }
5719 CloseHandle (sh);
5720 }
5721 else
5722 {
5723 /* CreateFile failed. */
5724 DWORD w32err2 = GetLastError ();
5725
5726 switch (w32err2)
5727 {
5728 case ERROR_FILE_NOT_FOUND:
5729 case ERROR_PATH_NOT_FOUND:
5730 errno = ENOENT;
5731 break;
5732 case ERROR_ACCESS_DENIED:
5733 case ERROR_TOO_MANY_OPEN_FILES:
5734 errno = EACCES;
5735 break;
5736 default:
5737 errno = EPERM;
5738 break;
5739 }
5740 }
5741 if (restore_privs)
5742 {
5743 restore_privilege (&privs);
5744 revert_to_self ();
5745 }
5746
5747 return retval;
5748 }
5749
5750 ssize_t
5751 readlinkat (int fd, char const *name, char *buffer,
5752 size_t buffer_size)
5753 {
5754 /* Rely on a hack: an open directory is modeled as file descriptor 0,
5755 as in fstatat. FIXME: Add proper support for readlinkat. */
5756 char fullname[MAX_UTF8_PATH];
5757
5758 if (fd != AT_FDCWD)
5759 {
5760 if (_snprintf (fullname, sizeof fullname, "%s/%s", dir_pathname, name)
5761 < 0)
5762 {
5763 errno = ENAMETOOLONG;
5764 return -1;
5765 }
5766 name = fullname;
5767 }
5768
5769 return readlink (name, buffer, buffer_size);
5770 }
5771
5772 /* If FILE is a symlink, return its target (stored in a static
5773 buffer); otherwise return FILE.
5774
5775 This function repeatedly resolves symlinks in the last component of
5776 a chain of symlink file names, as in foo -> bar -> baz -> ...,
5777 until it arrives at a file whose last component is not a symlink,
5778 or some error occurs. It returns the target of the last
5779 successfully resolved symlink in the chain. If it succeeds to
5780 resolve even a single symlink, the value returned is an absolute
5781 file name with backslashes (result of GetFullPathName). By
5782 contrast, if the original FILE is returned, it is unaltered.
5783
5784 Note: This function can set errno even if it succeeds.
5785
5786 Implementation note: we only resolve the last portion ("basename")
5787 of the argument FILE and of each following file in the chain,
5788 disregarding any possible symlinks in its leading directories.
5789 This is because Windows system calls and library functions
5790 transparently resolve symlinks in leading directories and return
5791 correct information, as long as the basename is not a symlink. */
5792 static char *
5793 chase_symlinks (const char *file)
5794 {
5795 static char target[MAX_UTF8_PATH];
5796 char link[MAX_UTF8_PATH];
5797 wchar_t target_w[MAX_PATH], link_w[MAX_PATH];
5798 char target_a[MAX_PATH], link_a[MAX_PATH];
5799 ssize_t res, link_len;
5800 int loop_count = 0;
5801
5802 if (is_windows_9x () == TRUE || !is_symlink (file))
5803 return (char *)file;
5804
5805 if (w32_unicode_filenames)
5806 {
5807 wchar_t file_w[MAX_PATH];
5808
5809 filename_to_utf16 (file, file_w);
5810 if (GetFullPathNameW (file_w, MAX_PATH, link_w, NULL) == 0)
5811 return (char *)file;
5812 filename_from_utf16 (link_w, link);
5813 }
5814 else
5815 {
5816 char file_a[MAX_PATH];
5817
5818 filename_to_ansi (file, file_a);
5819 if (GetFullPathNameA (file_a, MAX_PATH, link_a, NULL) == 0)
5820 return (char *)file;
5821 filename_from_ansi (link_a, link);
5822 }
5823 link_len = strlen (link);
5824
5825 target[0] = '\0';
5826 do {
5827
5828 /* Remove trailing slashes, as we want to resolve the last
5829 non-trivial part of the link name. */
5830 while (link_len > 3 && IS_DIRECTORY_SEP (link[link_len-1]))
5831 link[link_len--] = '\0';
5832
5833 res = readlink (link, target, MAX_UTF8_PATH);
5834 if (res > 0)
5835 {
5836 target[res] = '\0';
5837 if (!(IS_DEVICE_SEP (target[1])
5838 || (IS_DIRECTORY_SEP (target[0]) && IS_DIRECTORY_SEP (target[1]))))
5839 {
5840 /* Target is relative. Append it to the directory part of
5841 the symlink, then copy the result back to target. */
5842 char *p = link + link_len;
5843
5844 while (p > link && !IS_ANY_SEP (p[-1]))
5845 p--;
5846 strcpy (p, target);
5847 strcpy (target, link);
5848 }
5849 /* Resolve any "." and ".." to get a fully-qualified file name
5850 in link[] again. */
5851 if (w32_unicode_filenames)
5852 {
5853 filename_to_utf16 (target, target_w);
5854 link_len = GetFullPathNameW (target_w, MAX_PATH, link_w, NULL);
5855 if (link_len > 0)
5856 filename_from_utf16 (link_w, link);
5857 }
5858 else
5859 {
5860 filename_to_ansi (target, target_a);
5861 link_len = GetFullPathNameA (target_a, MAX_PATH, link_a, NULL);
5862 if (link_len > 0)
5863 filename_from_ansi (link_a, link);
5864 }
5865 link_len = strlen (link);
5866 }
5867 } while (res > 0 && link_len > 0 && ++loop_count <= 100);
5868
5869 if (loop_count > 100)
5870 errno = ELOOP;
5871
5872 if (target[0] == '\0') /* not a single call to readlink succeeded */
5873 return (char *)file;
5874 return target;
5875 }
5876
5877 \f
5878 /* Posix ACL emulation. */
5879
5880 int
5881 acl_valid (acl_t acl)
5882 {
5883 return is_valid_security_descriptor ((PSECURITY_DESCRIPTOR)acl) ? 0 : -1;
5884 }
5885
5886 char *
5887 acl_to_text (acl_t acl, ssize_t *size)
5888 {
5889 LPTSTR str_acl;
5890 SECURITY_INFORMATION flags =
5891 OWNER_SECURITY_INFORMATION |
5892 GROUP_SECURITY_INFORMATION |
5893 DACL_SECURITY_INFORMATION;
5894 char *retval = NULL;
5895 ULONG local_size;
5896 int e = errno;
5897
5898 errno = 0;
5899
5900 if (convert_sd_to_sddl ((PSECURITY_DESCRIPTOR)acl, SDDL_REVISION_1, flags, &str_acl, &local_size))
5901 {
5902 errno = e;
5903 /* We don't want to mix heaps, so we duplicate the string in our
5904 heap and free the one allocated by the API. */
5905 retval = xstrdup (str_acl);
5906 if (size)
5907 *size = local_size;
5908 LocalFree (str_acl);
5909 }
5910 else if (errno != ENOTSUP)
5911 errno = EINVAL;
5912
5913 return retval;
5914 }
5915
5916 acl_t
5917 acl_from_text (const char *acl_str)
5918 {
5919 PSECURITY_DESCRIPTOR psd, retval = NULL;
5920 ULONG sd_size;
5921 int e = errno;
5922
5923 errno = 0;
5924
5925 if (convert_sddl_to_sd (acl_str, SDDL_REVISION_1, &psd, &sd_size))
5926 {
5927 errno = e;
5928 retval = xmalloc (sd_size);
5929 memcpy (retval, psd, sd_size);
5930 LocalFree (psd);
5931 }
5932 else if (errno != ENOTSUP)
5933 errno = EINVAL;
5934
5935 return retval;
5936 }
5937
5938 int
5939 acl_free (void *ptr)
5940 {
5941 xfree (ptr);
5942 return 0;
5943 }
5944
5945 acl_t
5946 acl_get_file (const char *fname, acl_type_t type)
5947 {
5948 PSECURITY_DESCRIPTOR psd = NULL;
5949 const char *filename;
5950
5951 if (type == ACL_TYPE_ACCESS)
5952 {
5953 DWORD sd_len, err;
5954 SECURITY_INFORMATION si =
5955 OWNER_SECURITY_INFORMATION |
5956 GROUP_SECURITY_INFORMATION |
5957 DACL_SECURITY_INFORMATION ;
5958 int e = errno;
5959
5960 filename = map_w32_filename (fname, NULL);
5961 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
5962 fname = chase_symlinks (filename);
5963 else
5964 fname = filename;
5965
5966 errno = 0;
5967 if (!get_file_security (fname, si, psd, 0, &sd_len)
5968 && errno != ENOTSUP)
5969 {
5970 err = GetLastError ();
5971 if (err == ERROR_INSUFFICIENT_BUFFER)
5972 {
5973 psd = xmalloc (sd_len);
5974 if (!get_file_security (fname, si, psd, sd_len, &sd_len))
5975 {
5976 xfree (psd);
5977 errno = EIO;
5978 psd = NULL;
5979 }
5980 }
5981 else if (err == ERROR_FILE_NOT_FOUND
5982 || err == ERROR_PATH_NOT_FOUND
5983 /* ERROR_INVALID_NAME is what we get if
5984 w32-unicode-filenames is nil and the file cannot
5985 be encoded in the current ANSI codepage. */
5986 || err == ERROR_INVALID_NAME)
5987 errno = ENOENT;
5988 else
5989 errno = EIO;
5990 }
5991 else if (!errno)
5992 errno = e;
5993 }
5994 else if (type != ACL_TYPE_DEFAULT)
5995 errno = EINVAL;
5996
5997 return psd;
5998 }
5999
6000 int
6001 acl_set_file (const char *fname, acl_type_t type, acl_t acl)
6002 {
6003 TOKEN_PRIVILEGES old1, old2;
6004 DWORD err;
6005 int st = 0, retval = -1;
6006 SECURITY_INFORMATION flags = 0;
6007 PSID psidOwner, psidGroup;
6008 PACL pacl;
6009 BOOL dflt;
6010 BOOL dacl_present;
6011 int e;
6012 const char *filename;
6013
6014 if (acl_valid (acl) != 0
6015 || (type != ACL_TYPE_DEFAULT && type != ACL_TYPE_ACCESS))
6016 {
6017 errno = EINVAL;
6018 return -1;
6019 }
6020
6021 if (type == ACL_TYPE_DEFAULT)
6022 {
6023 errno = ENOSYS;
6024 return -1;
6025 }
6026
6027 filename = map_w32_filename (fname, NULL);
6028 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
6029 fname = chase_symlinks (filename);
6030 else
6031 fname = filename;
6032
6033 if (get_security_descriptor_owner ((PSECURITY_DESCRIPTOR)acl, &psidOwner,
6034 &dflt)
6035 && psidOwner)
6036 flags |= OWNER_SECURITY_INFORMATION;
6037 if (get_security_descriptor_group ((PSECURITY_DESCRIPTOR)acl, &psidGroup,
6038 &dflt)
6039 && psidGroup)
6040 flags |= GROUP_SECURITY_INFORMATION;
6041 if (get_security_descriptor_dacl ((PSECURITY_DESCRIPTOR)acl, &dacl_present,
6042 &pacl, &dflt)
6043 && dacl_present)
6044 flags |= DACL_SECURITY_INFORMATION;
6045 if (!flags)
6046 return 0;
6047
6048 /* According to KB-245153, setting the owner will succeed if either:
6049 (1) the caller is the user who will be the new owner, and has the
6050 SE_TAKE_OWNERSHIP privilege, or
6051 (2) the caller has the SE_RESTORE privilege, in which case she can
6052 set any valid user or group as the owner
6053
6054 We request below both SE_TAKE_OWNERSHIP and SE_RESTORE
6055 privileges, and disregard any failures in obtaining them. If
6056 these privileges cannot be obtained, and do not already exist in
6057 the calling thread's security token, this function could fail
6058 with EPERM. */
6059 if (enable_privilege (SE_TAKE_OWNERSHIP_NAME, TRUE, &old1))
6060 st++;
6061 if (enable_privilege (SE_RESTORE_NAME, TRUE, &old2))
6062 st++;
6063
6064 e = errno;
6065 errno = 0;
6066 /* SetFileSecurity is deprecated by MS, and sometimes fails when
6067 DACL inheritance is involved, but it seems to preserve ownership
6068 better than SetNamedSecurityInfo, which is important e.g., in
6069 copy-file. */
6070 if (!set_file_security (fname, flags, (PSECURITY_DESCRIPTOR)acl))
6071 {
6072 err = GetLastError ();
6073
6074 if (errno != ENOTSUP)
6075 err = set_named_security_info (fname, SE_FILE_OBJECT, flags,
6076 psidOwner, psidGroup, pacl, NULL);
6077 }
6078 else
6079 err = ERROR_SUCCESS;
6080 if (err != ERROR_SUCCESS)
6081 {
6082 if (errno == ENOTSUP)
6083 ;
6084 else if (err == ERROR_INVALID_OWNER
6085 || err == ERROR_NOT_ALL_ASSIGNED
6086 || err == ERROR_ACCESS_DENIED)
6087 {
6088 /* Maybe the requested ACL and the one the file already has
6089 are identical, in which case we can silently ignore the
6090 failure. (And no, Windows doesn't.) */
6091 acl_t current_acl = acl_get_file (fname, ACL_TYPE_ACCESS);
6092
6093 errno = EPERM;
6094 if (current_acl)
6095 {
6096 char *acl_from = acl_to_text (current_acl, NULL);
6097 char *acl_to = acl_to_text (acl, NULL);
6098
6099 if (acl_from && acl_to && xstrcasecmp (acl_from, acl_to) == 0)
6100 {
6101 retval = 0;
6102 errno = e;
6103 }
6104 if (acl_from)
6105 acl_free (acl_from);
6106 if (acl_to)
6107 acl_free (acl_to);
6108 acl_free (current_acl);
6109 }
6110 }
6111 else if (err == ERROR_FILE_NOT_FOUND
6112 || err == ERROR_PATH_NOT_FOUND
6113 /* ERROR_INVALID_NAME is what we get if
6114 w32-unicode-filenames is nil and the file cannot be
6115 encoded in the current ANSI codepage. */
6116 || err == ERROR_INVALID_NAME)
6117 errno = ENOENT;
6118 else
6119 errno = EACCES;
6120 }
6121 else
6122 {
6123 retval = 0;
6124 errno = e;
6125 }
6126
6127 if (st)
6128 {
6129 if (st >= 2)
6130 restore_privilege (&old2);
6131 restore_privilege (&old1);
6132 revert_to_self ();
6133 }
6134
6135 return retval;
6136 }
6137
6138 \f
6139 /* MS-Windows version of careadlinkat (cf. ../lib/careadlinkat.c). We
6140 have a fixed max size for file names, so we don't need the kind of
6141 alloc/malloc/realloc dance the gnulib version does. We also don't
6142 support FD-relative symlinks. */
6143 char *
6144 careadlinkat (int fd, char const *filename,
6145 char *buffer, size_t buffer_size,
6146 struct allocator const *alloc,
6147 ssize_t (*preadlinkat) (int, char const *, char *, size_t))
6148 {
6149 char linkname[MAX_UTF8_PATH];
6150 ssize_t link_size;
6151
6152 link_size = preadlinkat (fd, filename, linkname, sizeof(linkname));
6153
6154 if (link_size > 0)
6155 {
6156 char *retval = buffer;
6157
6158 linkname[link_size++] = '\0';
6159 if (link_size > buffer_size)
6160 retval = (char *)(alloc ? alloc->allocate : xmalloc) (link_size);
6161 if (retval)
6162 memcpy (retval, linkname, link_size);
6163
6164 return retval;
6165 }
6166 return NULL;
6167 }
6168
6169 int
6170 w32_copy_file (const char *from, const char *to,
6171 int keep_time, int preserve_ownership, int copy_acls)
6172 {
6173 acl_t acl = NULL;
6174 BOOL copy_result;
6175 wchar_t from_w[MAX_PATH], to_w[MAX_PATH];
6176 char from_a[MAX_PATH], to_a[MAX_PATH];
6177
6178 /* We ignore preserve_ownership for now. */
6179 preserve_ownership = preserve_ownership;
6180
6181 if (copy_acls)
6182 {
6183 acl = acl_get_file (from, ACL_TYPE_ACCESS);
6184 if (acl == NULL && acl_errno_valid (errno))
6185 return -2;
6186 }
6187 if (w32_unicode_filenames)
6188 {
6189 filename_to_utf16 (from, from_w);
6190 filename_to_utf16 (to, to_w);
6191 copy_result = CopyFileW (from_w, to_w, FALSE);
6192 }
6193 else
6194 {
6195 filename_to_ansi (from, from_a);
6196 filename_to_ansi (to, to_a);
6197 copy_result = CopyFileA (from_a, to_a, FALSE);
6198 }
6199 if (!copy_result)
6200 {
6201 /* CopyFile doesn't set errno when it fails. By far the most
6202 "popular" reason is that the target is read-only. */
6203 DWORD err = GetLastError ();
6204
6205 switch (err)
6206 {
6207 case ERROR_FILE_NOT_FOUND:
6208 errno = ENOENT;
6209 break;
6210 case ERROR_ACCESS_DENIED:
6211 errno = EACCES;
6212 break;
6213 case ERROR_ENCRYPTION_FAILED:
6214 errno = EIO;
6215 break;
6216 default:
6217 errno = EPERM;
6218 break;
6219 }
6220
6221 if (acl)
6222 acl_free (acl);
6223 return -1;
6224 }
6225 /* CopyFile retains the timestamp by default. However, see
6226 "Community Additions" for CopyFile: it sounds like that is not
6227 entirely true. Testing on Windows XP confirms that modified time
6228 is copied, but creation and last-access times are not.
6229 FIXME? */
6230 else if (!keep_time)
6231 {
6232 struct timespec now;
6233 DWORD attributes;
6234
6235 if (w32_unicode_filenames)
6236 {
6237 /* Ensure file is writable while its times are set. */
6238 attributes = GetFileAttributesW (to_w);
6239 SetFileAttributesW (to_w, attributes & ~FILE_ATTRIBUTE_READONLY);
6240 now = current_timespec ();
6241 if (set_file_times (-1, to, now, now))
6242 {
6243 /* Restore original attributes. */
6244 SetFileAttributesW (to_w, attributes);
6245 if (acl)
6246 acl_free (acl);
6247 return -3;
6248 }
6249 /* Restore original attributes. */
6250 SetFileAttributesW (to_w, attributes);
6251 }
6252 else
6253 {
6254 attributes = GetFileAttributesA (to_a);
6255 SetFileAttributesA (to_a, attributes & ~FILE_ATTRIBUTE_READONLY);
6256 now = current_timespec ();
6257 if (set_file_times (-1, to, now, now))
6258 {
6259 SetFileAttributesA (to_a, attributes);
6260 if (acl)
6261 acl_free (acl);
6262 return -3;
6263 }
6264 SetFileAttributesA (to_a, attributes);
6265 }
6266 }
6267 if (acl != NULL)
6268 {
6269 bool fail =
6270 acl_set_file (to, ACL_TYPE_ACCESS, acl) != 0;
6271 acl_free (acl);
6272 if (fail && acl_errno_valid (errno))
6273 return -4;
6274 }
6275
6276 return 0;
6277 }
6278
6279 \f
6280 /* Support for browsing other processes and their attributes. See
6281 process.c for the Lisp bindings. */
6282
6283 /* Helper wrapper functions. */
6284
6285 static HANDLE WINAPI
6286 create_toolhelp32_snapshot (DWORD Flags, DWORD Ignored)
6287 {
6288 static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot = NULL;
6289
6290 if (g_b_init_create_toolhelp32_snapshot == 0)
6291 {
6292 g_b_init_create_toolhelp32_snapshot = 1;
6293 s_pfn_Create_Toolhelp32_Snapshot = (CreateToolhelp32Snapshot_Proc)
6294 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6295 "CreateToolhelp32Snapshot");
6296 }
6297 if (s_pfn_Create_Toolhelp32_Snapshot == NULL)
6298 {
6299 return INVALID_HANDLE_VALUE;
6300 }
6301 return (s_pfn_Create_Toolhelp32_Snapshot (Flags, Ignored));
6302 }
6303
6304 static BOOL WINAPI
6305 process32_first (HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
6306 {
6307 static Process32First_Proc s_pfn_Process32_First = NULL;
6308
6309 if (g_b_init_process32_first == 0)
6310 {
6311 g_b_init_process32_first = 1;
6312 s_pfn_Process32_First = (Process32First_Proc)
6313 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6314 "Process32First");
6315 }
6316 if (s_pfn_Process32_First == NULL)
6317 {
6318 return FALSE;
6319 }
6320 return (s_pfn_Process32_First (hSnapshot, lppe));
6321 }
6322
6323 static BOOL WINAPI
6324 process32_next (HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
6325 {
6326 static Process32Next_Proc s_pfn_Process32_Next = NULL;
6327
6328 if (g_b_init_process32_next == 0)
6329 {
6330 g_b_init_process32_next = 1;
6331 s_pfn_Process32_Next = (Process32Next_Proc)
6332 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6333 "Process32Next");
6334 }
6335 if (s_pfn_Process32_Next == NULL)
6336 {
6337 return FALSE;
6338 }
6339 return (s_pfn_Process32_Next (hSnapshot, lppe));
6340 }
6341
6342 static BOOL WINAPI
6343 open_thread_token (HANDLE ThreadHandle,
6344 DWORD DesiredAccess,
6345 BOOL OpenAsSelf,
6346 PHANDLE TokenHandle)
6347 {
6348 static OpenThreadToken_Proc s_pfn_Open_Thread_Token = NULL;
6349 HMODULE hm_advapi32 = NULL;
6350 if (is_windows_9x () == TRUE)
6351 {
6352 SetLastError (ERROR_NOT_SUPPORTED);
6353 return FALSE;
6354 }
6355 if (g_b_init_open_thread_token == 0)
6356 {
6357 g_b_init_open_thread_token = 1;
6358 hm_advapi32 = LoadLibrary ("Advapi32.dll");
6359 s_pfn_Open_Thread_Token =
6360 (OpenThreadToken_Proc) GetProcAddress (hm_advapi32, "OpenThreadToken");
6361 }
6362 if (s_pfn_Open_Thread_Token == NULL)
6363 {
6364 SetLastError (ERROR_NOT_SUPPORTED);
6365 return FALSE;
6366 }
6367 return (
6368 s_pfn_Open_Thread_Token (
6369 ThreadHandle,
6370 DesiredAccess,
6371 OpenAsSelf,
6372 TokenHandle)
6373 );
6374 }
6375
6376 static BOOL WINAPI
6377 impersonate_self (SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
6378 {
6379 static ImpersonateSelf_Proc s_pfn_Impersonate_Self = NULL;
6380 HMODULE hm_advapi32 = NULL;
6381 if (is_windows_9x () == TRUE)
6382 {
6383 return FALSE;
6384 }
6385 if (g_b_init_impersonate_self == 0)
6386 {
6387 g_b_init_impersonate_self = 1;
6388 hm_advapi32 = LoadLibrary ("Advapi32.dll");
6389 s_pfn_Impersonate_Self =
6390 (ImpersonateSelf_Proc) GetProcAddress (hm_advapi32, "ImpersonateSelf");
6391 }
6392 if (s_pfn_Impersonate_Self == NULL)
6393 {
6394 return FALSE;
6395 }
6396 return s_pfn_Impersonate_Self (ImpersonationLevel);
6397 }
6398
6399 static BOOL WINAPI
6400 revert_to_self (void)
6401 {
6402 static RevertToSelf_Proc s_pfn_Revert_To_Self = NULL;
6403 HMODULE hm_advapi32 = NULL;
6404 if (is_windows_9x () == TRUE)
6405 {
6406 return FALSE;
6407 }
6408 if (g_b_init_revert_to_self == 0)
6409 {
6410 g_b_init_revert_to_self = 1;
6411 hm_advapi32 = LoadLibrary ("Advapi32.dll");
6412 s_pfn_Revert_To_Self =
6413 (RevertToSelf_Proc) GetProcAddress (hm_advapi32, "RevertToSelf");
6414 }
6415 if (s_pfn_Revert_To_Self == NULL)
6416 {
6417 return FALSE;
6418 }
6419 return s_pfn_Revert_To_Self ();
6420 }
6421
6422 static BOOL WINAPI
6423 get_process_memory_info (HANDLE h_proc,
6424 PPROCESS_MEMORY_COUNTERS mem_counters,
6425 DWORD bufsize)
6426 {
6427 static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info = NULL;
6428 HMODULE hm_psapi = NULL;
6429 if (is_windows_9x () == TRUE)
6430 {
6431 return FALSE;
6432 }
6433 if (g_b_init_get_process_memory_info == 0)
6434 {
6435 g_b_init_get_process_memory_info = 1;
6436 hm_psapi = LoadLibrary ("Psapi.dll");
6437 if (hm_psapi)
6438 s_pfn_Get_Process_Memory_Info = (GetProcessMemoryInfo_Proc)
6439 GetProcAddress (hm_psapi, "GetProcessMemoryInfo");
6440 }
6441 if (s_pfn_Get_Process_Memory_Info == NULL)
6442 {
6443 return FALSE;
6444 }
6445 return s_pfn_Get_Process_Memory_Info (h_proc, mem_counters, bufsize);
6446 }
6447
6448 static BOOL WINAPI
6449 get_process_working_set_size (HANDLE h_proc,
6450 PSIZE_T minrss,
6451 PSIZE_T maxrss)
6452 {
6453 static GetProcessWorkingSetSize_Proc
6454 s_pfn_Get_Process_Working_Set_Size = NULL;
6455
6456 if (is_windows_9x () == TRUE)
6457 {
6458 return FALSE;
6459 }
6460 if (g_b_init_get_process_working_set_size == 0)
6461 {
6462 g_b_init_get_process_working_set_size = 1;
6463 s_pfn_Get_Process_Working_Set_Size = (GetProcessWorkingSetSize_Proc)
6464 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6465 "GetProcessWorkingSetSize");
6466 }
6467 if (s_pfn_Get_Process_Working_Set_Size == NULL)
6468 {
6469 return FALSE;
6470 }
6471 return s_pfn_Get_Process_Working_Set_Size (h_proc, minrss, maxrss);
6472 }
6473
6474 static BOOL WINAPI
6475 global_memory_status (MEMORYSTATUS *buf)
6476 {
6477 static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status = NULL;
6478
6479 if (is_windows_9x () == TRUE)
6480 {
6481 return FALSE;
6482 }
6483 if (g_b_init_global_memory_status == 0)
6484 {
6485 g_b_init_global_memory_status = 1;
6486 s_pfn_Global_Memory_Status = (GlobalMemoryStatus_Proc)
6487 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6488 "GlobalMemoryStatus");
6489 }
6490 if (s_pfn_Global_Memory_Status == NULL)
6491 {
6492 return FALSE;
6493 }
6494 return s_pfn_Global_Memory_Status (buf);
6495 }
6496
6497 static BOOL WINAPI
6498 global_memory_status_ex (MEMORY_STATUS_EX *buf)
6499 {
6500 static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex = NULL;
6501
6502 if (is_windows_9x () == TRUE)
6503 {
6504 return FALSE;
6505 }
6506 if (g_b_init_global_memory_status_ex == 0)
6507 {
6508 g_b_init_global_memory_status_ex = 1;
6509 s_pfn_Global_Memory_Status_Ex = (GlobalMemoryStatusEx_Proc)
6510 GetProcAddress (GetModuleHandle ("kernel32.dll"),
6511 "GlobalMemoryStatusEx");
6512 }
6513 if (s_pfn_Global_Memory_Status_Ex == NULL)
6514 {
6515 return FALSE;
6516 }
6517 return s_pfn_Global_Memory_Status_Ex (buf);
6518 }
6519
6520 Lisp_Object
6521 list_system_processes (void)
6522 {
6523 struct gcpro gcpro1;
6524 Lisp_Object proclist = Qnil;
6525 HANDLE h_snapshot;
6526
6527 h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
6528
6529 if (h_snapshot != INVALID_HANDLE_VALUE)
6530 {
6531 PROCESSENTRY32 proc_entry;
6532 DWORD proc_id;
6533 BOOL res;
6534
6535 GCPRO1 (proclist);
6536
6537 proc_entry.dwSize = sizeof (PROCESSENTRY32);
6538 for (res = process32_first (h_snapshot, &proc_entry); res;
6539 res = process32_next (h_snapshot, &proc_entry))
6540 {
6541 proc_id = proc_entry.th32ProcessID;
6542 proclist = Fcons (make_fixnum_or_float (proc_id), proclist);
6543 }
6544
6545 CloseHandle (h_snapshot);
6546 UNGCPRO;
6547 proclist = Fnreverse (proclist);
6548 }
6549
6550 return proclist;
6551 }
6552
6553 static int
6554 enable_privilege (LPCTSTR priv_name, BOOL enable_p, TOKEN_PRIVILEGES *old_priv)
6555 {
6556 TOKEN_PRIVILEGES priv;
6557 DWORD priv_size = sizeof (priv);
6558 DWORD opriv_size = sizeof (*old_priv);
6559 HANDLE h_token = NULL;
6560 HANDLE h_thread = GetCurrentThread ();
6561 int ret_val = 0;
6562 BOOL res;
6563
6564 res = open_thread_token (h_thread,
6565 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
6566 FALSE, &h_token);
6567 if (!res && GetLastError () == ERROR_NO_TOKEN)
6568 {
6569 if (impersonate_self (SecurityImpersonation))
6570 res = open_thread_token (h_thread,
6571 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
6572 FALSE, &h_token);
6573 }
6574 if (res)
6575 {
6576 priv.PrivilegeCount = 1;
6577 priv.Privileges[0].Attributes = enable_p ? SE_PRIVILEGE_ENABLED : 0;
6578 LookupPrivilegeValue (NULL, priv_name, &priv.Privileges[0].Luid);
6579 if (AdjustTokenPrivileges (h_token, FALSE, &priv, priv_size,
6580 old_priv, &opriv_size)
6581 && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
6582 ret_val = 1;
6583 }
6584 if (h_token)
6585 CloseHandle (h_token);
6586
6587 return ret_val;
6588 }
6589
6590 static int
6591 restore_privilege (TOKEN_PRIVILEGES *priv)
6592 {
6593 DWORD priv_size = sizeof (*priv);
6594 HANDLE h_token = NULL;
6595 int ret_val = 0;
6596
6597 if (open_thread_token (GetCurrentThread (),
6598 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
6599 FALSE, &h_token))
6600 {
6601 if (AdjustTokenPrivileges (h_token, FALSE, priv, priv_size, NULL, NULL)
6602 && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
6603 ret_val = 1;
6604 }
6605 if (h_token)
6606 CloseHandle (h_token);
6607
6608 return ret_val;
6609 }
6610
6611 static Lisp_Object
6612 ltime (ULONGLONG time_100ns)
6613 {
6614 ULONGLONG time_sec = time_100ns / 10000000;
6615 int subsec = time_100ns % 10000000;
6616 return list4i (time_sec >> 16, time_sec & 0xffff,
6617 subsec / 10, subsec % 10 * 100000);
6618 }
6619
6620 #define U64_TO_LISP_TIME(time) ltime (time)
6621
6622 static int
6623 process_times (HANDLE h_proc, Lisp_Object *ctime, Lisp_Object *etime,
6624 Lisp_Object *stime, Lisp_Object *utime, Lisp_Object *ttime,
6625 double *pcpu)
6626 {
6627 FILETIME ft_creation, ft_exit, ft_kernel, ft_user, ft_current;
6628 ULONGLONG tem1, tem2, tem3, tem;
6629
6630 if (!h_proc
6631 || !get_process_times_fn
6632 || !(*get_process_times_fn) (h_proc, &ft_creation, &ft_exit,
6633 &ft_kernel, &ft_user))
6634 return 0;
6635
6636 GetSystemTimeAsFileTime (&ft_current);
6637
6638 FILETIME_TO_U64 (tem1, ft_kernel);
6639 *stime = U64_TO_LISP_TIME (tem1);
6640
6641 FILETIME_TO_U64 (tem2, ft_user);
6642 *utime = U64_TO_LISP_TIME (tem2);
6643
6644 tem3 = tem1 + tem2;
6645 *ttime = U64_TO_LISP_TIME (tem3);
6646
6647 FILETIME_TO_U64 (tem, ft_creation);
6648 /* Process no 4 (System) returns zero creation time. */
6649 if (tem)
6650 tem -= utc_base;
6651 *ctime = U64_TO_LISP_TIME (tem);
6652
6653 if (tem)
6654 {
6655 FILETIME_TO_U64 (tem3, ft_current);
6656 tem = (tem3 - utc_base) - tem;
6657 }
6658 *etime = U64_TO_LISP_TIME (tem);
6659
6660 if (tem)
6661 {
6662 *pcpu = 100.0 * (tem1 + tem2) / tem;
6663 if (*pcpu > 100)
6664 *pcpu = 100.0;
6665 }
6666 else
6667 *pcpu = 0;
6668
6669 return 1;
6670 }
6671
6672 Lisp_Object
6673 system_process_attributes (Lisp_Object pid)
6674 {
6675 struct gcpro gcpro1, gcpro2, gcpro3;
6676 Lisp_Object attrs = Qnil;
6677 Lisp_Object cmd_str, decoded_cmd, tem;
6678 HANDLE h_snapshot, h_proc;
6679 DWORD proc_id;
6680 int found_proc = 0;
6681 char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
6682 DWORD ulength = sizeof (uname), dlength = sizeof (domain), needed;
6683 DWORD glength = sizeof (gname);
6684 HANDLE token = NULL;
6685 SID_NAME_USE user_type;
6686 unsigned char *buf = NULL;
6687 DWORD blen = 0;
6688 TOKEN_USER user_token;
6689 TOKEN_PRIMARY_GROUP group_token;
6690 unsigned euid;
6691 unsigned egid;
6692 PROCESS_MEMORY_COUNTERS mem;
6693 PROCESS_MEMORY_COUNTERS_EX mem_ex;
6694 SIZE_T minrss, maxrss;
6695 MEMORYSTATUS memst;
6696 MEMORY_STATUS_EX memstex;
6697 double totphys = 0.0;
6698 Lisp_Object ctime, stime, utime, etime, ttime;
6699 double pcpu;
6700 BOOL result = FALSE;
6701
6702 CHECK_NUMBER_OR_FLOAT (pid);
6703 proc_id = FLOATP (pid) ? XFLOAT_DATA (pid) : XINT (pid);
6704
6705 h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
6706
6707 GCPRO3 (attrs, decoded_cmd, tem);
6708
6709 if (h_snapshot != INVALID_HANDLE_VALUE)
6710 {
6711 PROCESSENTRY32 pe;
6712 BOOL res;
6713
6714 pe.dwSize = sizeof (PROCESSENTRY32);
6715 for (res = process32_first (h_snapshot, &pe); res;
6716 res = process32_next (h_snapshot, &pe))
6717 {
6718 if (proc_id == pe.th32ProcessID)
6719 {
6720 if (proc_id == 0)
6721 decoded_cmd = build_string ("Idle");
6722 else
6723 {
6724 /* Decode the command name from locale-specific
6725 encoding. */
6726 cmd_str = build_unibyte_string (pe.szExeFile);
6727
6728 decoded_cmd =
6729 code_convert_string_norecord (cmd_str,
6730 Vlocale_coding_system, 0);
6731 }
6732 attrs = Fcons (Fcons (Qcomm, decoded_cmd), attrs);
6733 attrs = Fcons (Fcons (Qppid,
6734 make_fixnum_or_float (pe.th32ParentProcessID)),
6735 attrs);
6736 attrs = Fcons (Fcons (Qpri, make_number (pe.pcPriClassBase)),
6737 attrs);
6738 attrs = Fcons (Fcons (Qthcount,
6739 make_fixnum_or_float (pe.cntThreads)),
6740 attrs);
6741 found_proc = 1;
6742 break;
6743 }
6744 }
6745
6746 CloseHandle (h_snapshot);
6747 }
6748
6749 if (!found_proc)
6750 {
6751 UNGCPRO;
6752 return Qnil;
6753 }
6754
6755 h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
6756 FALSE, proc_id);
6757 /* If we were denied a handle to the process, try again after
6758 enabling the SeDebugPrivilege in our process. */
6759 if (!h_proc)
6760 {
6761 TOKEN_PRIVILEGES priv_current;
6762
6763 if (enable_privilege (SE_DEBUG_NAME, TRUE, &priv_current))
6764 {
6765 h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
6766 FALSE, proc_id);
6767 restore_privilege (&priv_current);
6768 revert_to_self ();
6769 }
6770 }
6771 if (h_proc)
6772 {
6773 result = open_process_token (h_proc, TOKEN_QUERY, &token);
6774 if (result)
6775 {
6776 result = get_token_information (token, TokenUser, NULL, 0, &blen);
6777 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
6778 {
6779 buf = xmalloc (blen);
6780 result = get_token_information (token, TokenUser,
6781 (LPVOID)buf, blen, &needed);
6782 if (result)
6783 {
6784 memcpy (&user_token, buf, sizeof (user_token));
6785 if (!w32_cached_id (user_token.User.Sid, &euid, uname))
6786 {
6787 euid = get_rid (user_token.User.Sid);
6788 result = lookup_account_sid (NULL, user_token.User.Sid,
6789 uname, &ulength,
6790 domain, &dlength,
6791 &user_type);
6792 if (result)
6793 w32_add_to_cache (user_token.User.Sid, euid, uname);
6794 else
6795 {
6796 strcpy (uname, "unknown");
6797 result = TRUE;
6798 }
6799 }
6800 ulength = strlen (uname);
6801 }
6802 }
6803 }
6804 if (result)
6805 {
6806 /* Determine a reasonable euid and gid values. */
6807 if (xstrcasecmp ("administrator", uname) == 0)
6808 {
6809 euid = 500; /* well-known Administrator uid */
6810 egid = 513; /* well-known None gid */
6811 }
6812 else
6813 {
6814 /* Get group id and name. */
6815 result = get_token_information (token, TokenPrimaryGroup,
6816 (LPVOID)buf, blen, &needed);
6817 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
6818 {
6819 buf = xrealloc (buf, blen = needed);
6820 result = get_token_information (token, TokenPrimaryGroup,
6821 (LPVOID)buf, blen, &needed);
6822 }
6823 if (result)
6824 {
6825 memcpy (&group_token, buf, sizeof (group_token));
6826 if (!w32_cached_id (group_token.PrimaryGroup, &egid, gname))
6827 {
6828 egid = get_rid (group_token.PrimaryGroup);
6829 dlength = sizeof (domain);
6830 result =
6831 lookup_account_sid (NULL, group_token.PrimaryGroup,
6832 gname, &glength, NULL, &dlength,
6833 &user_type);
6834 if (result)
6835 w32_add_to_cache (group_token.PrimaryGroup,
6836 egid, gname);
6837 else
6838 {
6839 strcpy (gname, "None");
6840 result = TRUE;
6841 }
6842 }
6843 glength = strlen (gname);
6844 }
6845 }
6846 }
6847 xfree (buf);
6848 }
6849 if (!result)
6850 {
6851 if (!is_windows_9x ())
6852 {
6853 /* We couldn't open the process token, presumably because of
6854 insufficient access rights. Assume this process is run
6855 by the system. */
6856 strcpy (uname, "SYSTEM");
6857 strcpy (gname, "None");
6858 euid = 18; /* SYSTEM */
6859 egid = 513; /* None */
6860 glength = strlen (gname);
6861 ulength = strlen (uname);
6862 }
6863 /* If we are running under Windows 9X, where security calls are
6864 not supported, we assume all processes are run by the current
6865 user. */
6866 else if (GetUserName (uname, &ulength))
6867 {
6868 if (xstrcasecmp ("administrator", uname) == 0)
6869 euid = 0;
6870 else
6871 euid = 123;
6872 egid = euid;
6873 strcpy (gname, "None");
6874 glength = strlen (gname);
6875 ulength = strlen (uname);
6876 }
6877 else
6878 {
6879 euid = 123;
6880 egid = 123;
6881 strcpy (uname, "administrator");
6882 ulength = strlen (uname);
6883 strcpy (gname, "None");
6884 glength = strlen (gname);
6885 }
6886 if (token)
6887 CloseHandle (token);
6888 }
6889
6890 attrs = Fcons (Fcons (Qeuid, make_fixnum_or_float (euid)), attrs);
6891 tem = make_unibyte_string (uname, ulength);
6892 attrs = Fcons (Fcons (Quser,
6893 code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
6894 attrs);
6895 attrs = Fcons (Fcons (Qegid, make_fixnum_or_float (egid)), attrs);
6896 tem = make_unibyte_string (gname, glength);
6897 attrs = Fcons (Fcons (Qgroup,
6898 code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
6899 attrs);
6900
6901 if (global_memory_status_ex (&memstex))
6902 #if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
6903 totphys = memstex.ullTotalPhys / 1024.0;
6904 #else
6905 /* Visual Studio 6 cannot convert an unsigned __int64 type to
6906 double, so we need to do this for it... */
6907 {
6908 DWORD tot_hi = memstex.ullTotalPhys >> 32;
6909 DWORD tot_md = (memstex.ullTotalPhys & 0x00000000ffffffff) >> 10;
6910 DWORD tot_lo = memstex.ullTotalPhys % 1024;
6911
6912 totphys = tot_hi * 4194304.0 + tot_md + tot_lo / 1024.0;
6913 }
6914 #endif /* __GNUC__ || _MSC_VER >= 1300 */
6915 else if (global_memory_status (&memst))
6916 totphys = memst.dwTotalPhys / 1024.0;
6917
6918 if (h_proc
6919 && get_process_memory_info (h_proc, (PROCESS_MEMORY_COUNTERS *)&mem_ex,
6920 sizeof (mem_ex)))
6921 {
6922 SIZE_T rss = mem_ex.WorkingSetSize / 1024;
6923
6924 attrs = Fcons (Fcons (Qmajflt,
6925 make_fixnum_or_float (mem_ex.PageFaultCount)),
6926 attrs);
6927 attrs = Fcons (Fcons (Qvsize,
6928 make_fixnum_or_float (mem_ex.PrivateUsage / 1024)),
6929 attrs);
6930 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (rss)), attrs);
6931 if (totphys)
6932 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
6933 }
6934 else if (h_proc
6935 && get_process_memory_info (h_proc, &mem, sizeof (mem)))
6936 {
6937 SIZE_T rss = mem_ex.WorkingSetSize / 1024;
6938
6939 attrs = Fcons (Fcons (Qmajflt,
6940 make_fixnum_or_float (mem.PageFaultCount)),
6941 attrs);
6942 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (rss)), attrs);
6943 if (totphys)
6944 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
6945 }
6946 else if (h_proc
6947 && get_process_working_set_size (h_proc, &minrss, &maxrss))
6948 {
6949 DWORD rss = maxrss / 1024;
6950
6951 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (maxrss / 1024)), attrs);
6952 if (totphys)
6953 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
6954 }
6955
6956 if (process_times (h_proc, &ctime, &etime, &stime, &utime, &ttime, &pcpu))
6957 {
6958 attrs = Fcons (Fcons (Qutime, utime), attrs);
6959 attrs = Fcons (Fcons (Qstime, stime), attrs);
6960 attrs = Fcons (Fcons (Qtime, ttime), attrs);
6961 attrs = Fcons (Fcons (Qstart, ctime), attrs);
6962 attrs = Fcons (Fcons (Qetime, etime), attrs);
6963 attrs = Fcons (Fcons (Qpcpu, make_float (pcpu)), attrs);
6964 }
6965
6966 /* FIXME: Retrieve command line by walking the PEB of the process. */
6967
6968 if (h_proc)
6969 CloseHandle (h_proc);
6970 UNGCPRO;
6971 return attrs;
6972 }
6973
6974 int
6975 w32_memory_info (unsigned long long *totalram, unsigned long long *freeram,
6976 unsigned long long *totalswap, unsigned long long *freeswap)
6977 {
6978 MEMORYSTATUS memst;
6979 MEMORY_STATUS_EX memstex;
6980
6981 /* Use GlobalMemoryStatusEx if available, as it can report more than
6982 2GB of memory. */
6983 if (global_memory_status_ex (&memstex))
6984 {
6985 *totalram = memstex.ullTotalPhys;
6986 *freeram = memstex.ullAvailPhys;
6987 *totalswap = memstex.ullTotalPageFile;
6988 *freeswap = memstex.ullAvailPageFile;
6989 return 0;
6990 }
6991 else if (global_memory_status (&memst))
6992 {
6993 *totalram = memst.dwTotalPhys;
6994 *freeram = memst.dwAvailPhys;
6995 *totalswap = memst.dwTotalPageFile;
6996 *freeswap = memst.dwAvailPageFile;
6997 return 0;
6998 }
6999 else
7000 return -1;
7001 }
7002
7003 \f
7004 /* Wrappers for winsock functions to map between our file descriptors
7005 and winsock's handles; also set h_errno for convenience.
7006
7007 To allow Emacs to run on systems which don't have winsock support
7008 installed, we dynamically link to winsock on startup if present, and
7009 otherwise provide the minimum necessary functionality
7010 (eg. gethostname). */
7011
7012 /* function pointers for relevant socket functions */
7013 int (PASCAL *pfn_WSAStartup) (WORD wVersionRequired, LPWSADATA lpWSAData);
7014 void (PASCAL *pfn_WSASetLastError) (int iError);
7015 int (PASCAL *pfn_WSAGetLastError) (void);
7016 int (PASCAL *pfn_WSAEventSelect) (SOCKET s, HANDLE hEventObject, long lNetworkEvents);
7017 HANDLE (PASCAL *pfn_WSACreateEvent) (void);
7018 int (PASCAL *pfn_WSACloseEvent) (HANDLE hEvent);
7019 int (PASCAL *pfn_socket) (int af, int type, int protocol);
7020 int (PASCAL *pfn_bind) (SOCKET s, const struct sockaddr *addr, int namelen);
7021 int (PASCAL *pfn_connect) (SOCKET s, const struct sockaddr *addr, int namelen);
7022 int (PASCAL *pfn_ioctlsocket) (SOCKET s, long cmd, u_long *argp);
7023 int (PASCAL *pfn_recv) (SOCKET s, char * buf, int len, int flags);
7024 int (PASCAL *pfn_send) (SOCKET s, const char * buf, int len, int flags);
7025 int (PASCAL *pfn_closesocket) (SOCKET s);
7026 int (PASCAL *pfn_shutdown) (SOCKET s, int how);
7027 int (PASCAL *pfn_WSACleanup) (void);
7028
7029 u_short (PASCAL *pfn_htons) (u_short hostshort);
7030 u_short (PASCAL *pfn_ntohs) (u_short netshort);
7031 unsigned long (PASCAL *pfn_inet_addr) (const char * cp);
7032 int (PASCAL *pfn_gethostname) (char * name, int namelen);
7033 struct hostent * (PASCAL *pfn_gethostbyname) (const char * name);
7034 struct servent * (PASCAL *pfn_getservbyname) (const char * name, const char * proto);
7035 int (PASCAL *pfn_getpeername) (SOCKET s, struct sockaddr *addr, int * namelen);
7036 int (PASCAL *pfn_setsockopt) (SOCKET s, int level, int optname,
7037 const char * optval, int optlen);
7038 int (PASCAL *pfn_listen) (SOCKET s, int backlog);
7039 int (PASCAL *pfn_getsockname) (SOCKET s, struct sockaddr * name,
7040 int * namelen);
7041 SOCKET (PASCAL *pfn_accept) (SOCKET s, struct sockaddr * addr, int * addrlen);
7042 int (PASCAL *pfn_recvfrom) (SOCKET s, char * buf, int len, int flags,
7043 struct sockaddr * from, int * fromlen);
7044 int (PASCAL *pfn_sendto) (SOCKET s, const char * buf, int len, int flags,
7045 const struct sockaddr * to, int tolen);
7046
7047 /* SetHandleInformation is only needed to make sockets non-inheritable. */
7048 BOOL (WINAPI *pfn_SetHandleInformation) (HANDLE object, DWORD mask, DWORD flags);
7049 #ifndef HANDLE_FLAG_INHERIT
7050 #define HANDLE_FLAG_INHERIT 1
7051 #endif
7052
7053 HANDLE winsock_lib;
7054 static int winsock_inuse;
7055
7056 BOOL
7057 term_winsock (void)
7058 {
7059 if (winsock_lib != NULL && winsock_inuse == 0)
7060 {
7061 release_listen_threads ();
7062 /* Not sure what would cause WSAENETDOWN, or even if it can happen
7063 after WSAStartup returns successfully, but it seems reasonable
7064 to allow unloading winsock anyway in that case. */
7065 if (pfn_WSACleanup () == 0 ||
7066 pfn_WSAGetLastError () == WSAENETDOWN)
7067 {
7068 if (FreeLibrary (winsock_lib))
7069 winsock_lib = NULL;
7070 return TRUE;
7071 }
7072 }
7073 return FALSE;
7074 }
7075
7076 BOOL
7077 init_winsock (int load_now)
7078 {
7079 WSADATA winsockData;
7080
7081 if (winsock_lib != NULL)
7082 return TRUE;
7083
7084 pfn_SetHandleInformation
7085 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
7086 "SetHandleInformation");
7087
7088 winsock_lib = LoadLibrary ("Ws2_32.dll");
7089
7090 if (winsock_lib != NULL)
7091 {
7092 /* dynamically link to socket functions */
7093
7094 #define LOAD_PROC(fn) \
7095 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
7096 goto fail;
7097
7098 LOAD_PROC (WSAStartup);
7099 LOAD_PROC (WSASetLastError);
7100 LOAD_PROC (WSAGetLastError);
7101 LOAD_PROC (WSAEventSelect);
7102 LOAD_PROC (WSACreateEvent);
7103 LOAD_PROC (WSACloseEvent);
7104 LOAD_PROC (socket);
7105 LOAD_PROC (bind);
7106 LOAD_PROC (connect);
7107 LOAD_PROC (ioctlsocket);
7108 LOAD_PROC (recv);
7109 LOAD_PROC (send);
7110 LOAD_PROC (closesocket);
7111 LOAD_PROC (shutdown);
7112 LOAD_PROC (htons);
7113 LOAD_PROC (ntohs);
7114 LOAD_PROC (inet_addr);
7115 LOAD_PROC (gethostname);
7116 LOAD_PROC (gethostbyname);
7117 LOAD_PROC (getservbyname);
7118 LOAD_PROC (getpeername);
7119 LOAD_PROC (WSACleanup);
7120 LOAD_PROC (setsockopt);
7121 LOAD_PROC (listen);
7122 LOAD_PROC (getsockname);
7123 LOAD_PROC (accept);
7124 LOAD_PROC (recvfrom);
7125 LOAD_PROC (sendto);
7126 #undef LOAD_PROC
7127
7128 /* specify version 1.1 of winsock */
7129 if (pfn_WSAStartup (0x101, &winsockData) == 0)
7130 {
7131 if (winsockData.wVersion != 0x101)
7132 goto fail;
7133
7134 if (!load_now)
7135 {
7136 /* Report that winsock exists and is usable, but leave
7137 socket functions disabled. I am assuming that calling
7138 WSAStartup does not require any network interaction,
7139 and in particular does not cause or require a dial-up
7140 connection to be established. */
7141
7142 pfn_WSACleanup ();
7143 FreeLibrary (winsock_lib);
7144 winsock_lib = NULL;
7145 }
7146 winsock_inuse = 0;
7147 return TRUE;
7148 }
7149
7150 fail:
7151 FreeLibrary (winsock_lib);
7152 winsock_lib = NULL;
7153 }
7154
7155 return FALSE;
7156 }
7157
7158
7159 int h_errno = 0;
7160
7161 /* Function to map winsock error codes to errno codes for those errno
7162 code defined in errno.h (errno values not defined by errno.h are
7163 already in nt/inc/sys/socket.h). */
7164 static void
7165 set_errno (void)
7166 {
7167 int wsa_err;
7168
7169 h_errno = 0;
7170 if (winsock_lib == NULL)
7171 wsa_err = EINVAL;
7172 else
7173 wsa_err = pfn_WSAGetLastError ();
7174
7175 switch (wsa_err)
7176 {
7177 case WSAEACCES: errno = EACCES; break;
7178 case WSAEBADF: errno = EBADF; break;
7179 case WSAEFAULT: errno = EFAULT; break;
7180 case WSAEINTR: errno = EINTR; break;
7181 case WSAEINVAL: errno = EINVAL; break;
7182 case WSAEMFILE: errno = EMFILE; break;
7183 case WSAENAMETOOLONG: errno = ENAMETOOLONG; break;
7184 case WSAENOTEMPTY: errno = ENOTEMPTY; break;
7185 default: errno = wsa_err; break;
7186 }
7187 }
7188
7189 static void
7190 check_errno (void)
7191 {
7192 h_errno = 0;
7193 if (winsock_lib != NULL)
7194 pfn_WSASetLastError (0);
7195 }
7196
7197 /* Extend strerror to handle the winsock-specific error codes. */
7198 struct {
7199 int errnum;
7200 char * msg;
7201 } _wsa_errlist[] = {
7202 {WSAEINTR , "Interrupted function call"},
7203 {WSAEBADF , "Bad file descriptor"},
7204 {WSAEACCES , "Permission denied"},
7205 {WSAEFAULT , "Bad address"},
7206 {WSAEINVAL , "Invalid argument"},
7207 {WSAEMFILE , "Too many open files"},
7208
7209 {WSAEWOULDBLOCK , "Resource temporarily unavailable"},
7210 {WSAEINPROGRESS , "Operation now in progress"},
7211 {WSAEALREADY , "Operation already in progress"},
7212 {WSAENOTSOCK , "Socket operation on non-socket"},
7213 {WSAEDESTADDRREQ , "Destination address required"},
7214 {WSAEMSGSIZE , "Message too long"},
7215 {WSAEPROTOTYPE , "Protocol wrong type for socket"},
7216 {WSAENOPROTOOPT , "Bad protocol option"},
7217 {WSAEPROTONOSUPPORT , "Protocol not supported"},
7218 {WSAESOCKTNOSUPPORT , "Socket type not supported"},
7219 {WSAEOPNOTSUPP , "Operation not supported"},
7220 {WSAEPFNOSUPPORT , "Protocol family not supported"},
7221 {WSAEAFNOSUPPORT , "Address family not supported by protocol family"},
7222 {WSAEADDRINUSE , "Address already in use"},
7223 {WSAEADDRNOTAVAIL , "Cannot assign requested address"},
7224 {WSAENETDOWN , "Network is down"},
7225 {WSAENETUNREACH , "Network is unreachable"},
7226 {WSAENETRESET , "Network dropped connection on reset"},
7227 {WSAECONNABORTED , "Software caused connection abort"},
7228 {WSAECONNRESET , "Connection reset by peer"},
7229 {WSAENOBUFS , "No buffer space available"},
7230 {WSAEISCONN , "Socket is already connected"},
7231 {WSAENOTCONN , "Socket is not connected"},
7232 {WSAESHUTDOWN , "Cannot send after socket shutdown"},
7233 {WSAETOOMANYREFS , "Too many references"}, /* not sure */
7234 {WSAETIMEDOUT , "Connection timed out"},
7235 {WSAECONNREFUSED , "Connection refused"},
7236 {WSAELOOP , "Network loop"}, /* not sure */
7237 {WSAENAMETOOLONG , "Name is too long"},
7238 {WSAEHOSTDOWN , "Host is down"},
7239 {WSAEHOSTUNREACH , "No route to host"},
7240 {WSAENOTEMPTY , "Buffer not empty"}, /* not sure */
7241 {WSAEPROCLIM , "Too many processes"},
7242 {WSAEUSERS , "Too many users"}, /* not sure */
7243 {WSAEDQUOT , "Double quote in host name"}, /* really not sure */
7244 {WSAESTALE , "Data is stale"}, /* not sure */
7245 {WSAEREMOTE , "Remote error"}, /* not sure */
7246
7247 {WSASYSNOTREADY , "Network subsystem is unavailable"},
7248 {WSAVERNOTSUPPORTED , "WINSOCK.DLL version out of range"},
7249 {WSANOTINITIALISED , "Winsock not initialized successfully"},
7250 {WSAEDISCON , "Graceful shutdown in progress"},
7251 #ifdef WSAENOMORE
7252 {WSAENOMORE , "No more operations allowed"}, /* not sure */
7253 {WSAECANCELLED , "Operation cancelled"}, /* not sure */
7254 {WSAEINVALIDPROCTABLE , "Invalid procedure table from service provider"},
7255 {WSAEINVALIDPROVIDER , "Invalid service provider version number"},
7256 {WSAEPROVIDERFAILEDINIT , "Unable to initialize a service provider"},
7257 {WSASYSCALLFAILURE , "System call failure"},
7258 {WSASERVICE_NOT_FOUND , "Service not found"}, /* not sure */
7259 {WSATYPE_NOT_FOUND , "Class type not found"},
7260 {WSA_E_NO_MORE , "No more resources available"}, /* really not sure */
7261 {WSA_E_CANCELLED , "Operation already cancelled"}, /* really not sure */
7262 {WSAEREFUSED , "Operation refused"}, /* not sure */
7263 #endif
7264
7265 {WSAHOST_NOT_FOUND , "Host not found"},
7266 {WSATRY_AGAIN , "Authoritative host not found during name lookup"},
7267 {WSANO_RECOVERY , "Non-recoverable error during name lookup"},
7268 {WSANO_DATA , "Valid name, no data record of requested type"},
7269
7270 {-1, NULL}
7271 };
7272
7273 char *
7274 sys_strerror (int error_no)
7275 {
7276 int i;
7277 static char unknown_msg[40];
7278
7279 if (error_no >= 0 && error_no < sys_nerr)
7280 return sys_errlist[error_no];
7281
7282 for (i = 0; _wsa_errlist[i].errnum >= 0; i++)
7283 if (_wsa_errlist[i].errnum == error_no)
7284 return _wsa_errlist[i].msg;
7285
7286 sprintf (unknown_msg, "Unidentified error: %d", error_no);
7287 return unknown_msg;
7288 }
7289
7290 /* [andrewi 3-May-96] I've had conflicting results using both methods,
7291 but I believe the method of keeping the socket handle separate (and
7292 insuring it is not inheritable) is the correct one. */
7293
7294 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
7295
7296 static int socket_to_fd (SOCKET s);
7297
7298 int
7299 sys_socket (int af, int type, int protocol)
7300 {
7301 SOCKET s;
7302
7303 if (winsock_lib == NULL)
7304 {
7305 errno = ENETDOWN;
7306 return INVALID_SOCKET;
7307 }
7308
7309 check_errno ();
7310
7311 /* call the real socket function */
7312 s = pfn_socket (af, type, protocol);
7313
7314 if (s != INVALID_SOCKET)
7315 return socket_to_fd (s);
7316
7317 set_errno ();
7318 return -1;
7319 }
7320
7321 /* Convert a SOCKET to a file descriptor. */
7322 static int
7323 socket_to_fd (SOCKET s)
7324 {
7325 int fd;
7326 child_process * cp;
7327
7328 /* Although under NT 3.5 _open_osfhandle will accept a socket
7329 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
7330 that does not work under NT 3.1. However, we can get the same
7331 effect by using a backdoor function to replace an existing
7332 descriptor handle with the one we want. */
7333
7334 /* allocate a file descriptor (with appropriate flags) */
7335 fd = _open ("NUL:", _O_RDWR);
7336 if (fd >= 0)
7337 {
7338 /* Make a non-inheritable copy of the socket handle. Note
7339 that it is possible that sockets aren't actually kernel
7340 handles, which appears to be the case on Windows 9x when
7341 the MS Proxy winsock client is installed. */
7342 {
7343 /* Apparently there is a bug in NT 3.51 with some service
7344 packs, which prevents using DuplicateHandle to make a
7345 socket handle non-inheritable (causes WSACleanup to
7346 hang). The work-around is to use SetHandleInformation
7347 instead if it is available and implemented. */
7348 if (pfn_SetHandleInformation)
7349 {
7350 pfn_SetHandleInformation ((HANDLE) s, HANDLE_FLAG_INHERIT, 0);
7351 }
7352 else
7353 {
7354 HANDLE parent = GetCurrentProcess ();
7355 HANDLE new_s = INVALID_HANDLE_VALUE;
7356
7357 if (DuplicateHandle (parent,
7358 (HANDLE) s,
7359 parent,
7360 &new_s,
7361 0,
7362 FALSE,
7363 DUPLICATE_SAME_ACCESS))
7364 {
7365 /* It is possible that DuplicateHandle succeeds even
7366 though the socket wasn't really a kernel handle,
7367 because a real handle has the same value. So
7368 test whether the new handle really is a socket. */
7369 long nonblocking = 0;
7370 if (pfn_ioctlsocket ((SOCKET) new_s, FIONBIO, &nonblocking) == 0)
7371 {
7372 pfn_closesocket (s);
7373 s = (SOCKET) new_s;
7374 }
7375 else
7376 {
7377 CloseHandle (new_s);
7378 }
7379 }
7380 }
7381 }
7382 eassert (fd < MAXDESC);
7383 fd_info[fd].hnd = (HANDLE) s;
7384
7385 /* set our own internal flags */
7386 fd_info[fd].flags = FILE_SOCKET | FILE_BINARY | FILE_READ | FILE_WRITE;
7387
7388 cp = new_child ();
7389 if (cp)
7390 {
7391 cp->fd = fd;
7392 cp->status = STATUS_READ_ACKNOWLEDGED;
7393
7394 /* attach child_process to fd_info */
7395 if (fd_info[ fd ].cp != NULL)
7396 {
7397 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd));
7398 emacs_abort ();
7399 }
7400
7401 fd_info[ fd ].cp = cp;
7402
7403 /* success! */
7404 winsock_inuse++; /* count open sockets */
7405 return fd;
7406 }
7407
7408 /* clean up */
7409 _close (fd);
7410 }
7411 else
7412 pfn_closesocket (s);
7413 errno = EMFILE;
7414 return -1;
7415 }
7416
7417 int
7418 sys_bind (int s, const struct sockaddr * addr, int namelen)
7419 {
7420 if (winsock_lib == NULL)
7421 {
7422 errno = ENOTSOCK;
7423 return SOCKET_ERROR;
7424 }
7425
7426 check_errno ();
7427 if (fd_info[s].flags & FILE_SOCKET)
7428 {
7429 int rc = pfn_bind (SOCK_HANDLE (s), addr, namelen);
7430 if (rc == SOCKET_ERROR)
7431 set_errno ();
7432 return rc;
7433 }
7434 errno = ENOTSOCK;
7435 return SOCKET_ERROR;
7436 }
7437
7438 int
7439 sys_connect (int s, const struct sockaddr * name, int namelen)
7440 {
7441 if (winsock_lib == NULL)
7442 {
7443 errno = ENOTSOCK;
7444 return SOCKET_ERROR;
7445 }
7446
7447 check_errno ();
7448 if (fd_info[s].flags & FILE_SOCKET)
7449 {
7450 int rc = pfn_connect (SOCK_HANDLE (s), name, namelen);
7451 if (rc == SOCKET_ERROR)
7452 set_errno ();
7453 return rc;
7454 }
7455 errno = ENOTSOCK;
7456 return SOCKET_ERROR;
7457 }
7458
7459 u_short
7460 sys_htons (u_short hostshort)
7461 {
7462 return (winsock_lib != NULL) ?
7463 pfn_htons (hostshort) : hostshort;
7464 }
7465
7466 u_short
7467 sys_ntohs (u_short netshort)
7468 {
7469 return (winsock_lib != NULL) ?
7470 pfn_ntohs (netshort) : netshort;
7471 }
7472
7473 unsigned long
7474 sys_inet_addr (const char * cp)
7475 {
7476 return (winsock_lib != NULL) ?
7477 pfn_inet_addr (cp) : INADDR_NONE;
7478 }
7479
7480 int
7481 sys_gethostname (char * name, int namelen)
7482 {
7483 if (winsock_lib != NULL)
7484 {
7485 int retval;
7486
7487 check_errno ();
7488 retval = pfn_gethostname (name, namelen);
7489 if (retval == SOCKET_ERROR)
7490 set_errno ();
7491 return retval;
7492 }
7493
7494 if (namelen > MAX_COMPUTERNAME_LENGTH)
7495 return !GetComputerName (name, (DWORD *)&namelen);
7496
7497 errno = EFAULT;
7498 return SOCKET_ERROR;
7499 }
7500
7501 struct hostent *
7502 sys_gethostbyname (const char * name)
7503 {
7504 struct hostent * host;
7505 int h_err = h_errno;
7506
7507 if (winsock_lib == NULL)
7508 {
7509 h_errno = NO_RECOVERY;
7510 errno = ENETDOWN;
7511 return NULL;
7512 }
7513
7514 check_errno ();
7515 host = pfn_gethostbyname (name);
7516 if (!host)
7517 {
7518 set_errno ();
7519 h_errno = errno;
7520 }
7521 else
7522 h_errno = h_err;
7523 return host;
7524 }
7525
7526 struct servent *
7527 sys_getservbyname (const char * name, const char * proto)
7528 {
7529 struct servent * serv;
7530
7531 if (winsock_lib == NULL)
7532 {
7533 errno = ENETDOWN;
7534 return NULL;
7535 }
7536
7537 check_errno ();
7538 serv = pfn_getservbyname (name, proto);
7539 if (!serv)
7540 set_errno ();
7541 return serv;
7542 }
7543
7544 int
7545 sys_getpeername (int s, struct sockaddr *addr, int * namelen)
7546 {
7547 if (winsock_lib == NULL)
7548 {
7549 errno = ENETDOWN;
7550 return SOCKET_ERROR;
7551 }
7552
7553 check_errno ();
7554 if (fd_info[s].flags & FILE_SOCKET)
7555 {
7556 int rc = pfn_getpeername (SOCK_HANDLE (s), addr, namelen);
7557 if (rc == SOCKET_ERROR)
7558 set_errno ();
7559 return rc;
7560 }
7561 errno = ENOTSOCK;
7562 return SOCKET_ERROR;
7563 }
7564
7565 int
7566 sys_shutdown (int s, int how)
7567 {
7568 if (winsock_lib == NULL)
7569 {
7570 errno = ENETDOWN;
7571 return SOCKET_ERROR;
7572 }
7573
7574 check_errno ();
7575 if (fd_info[s].flags & FILE_SOCKET)
7576 {
7577 int rc = pfn_shutdown (SOCK_HANDLE (s), how);
7578 if (rc == SOCKET_ERROR)
7579 set_errno ();
7580 return rc;
7581 }
7582 errno = ENOTSOCK;
7583 return SOCKET_ERROR;
7584 }
7585
7586 int
7587 sys_setsockopt (int s, int level, int optname, const void * optval, int optlen)
7588 {
7589 if (winsock_lib == NULL)
7590 {
7591 errno = ENETDOWN;
7592 return SOCKET_ERROR;
7593 }
7594
7595 check_errno ();
7596 if (fd_info[s].flags & FILE_SOCKET)
7597 {
7598 int rc = pfn_setsockopt (SOCK_HANDLE (s), level, optname,
7599 (const char *)optval, optlen);
7600 if (rc == SOCKET_ERROR)
7601 set_errno ();
7602 return rc;
7603 }
7604 errno = ENOTSOCK;
7605 return SOCKET_ERROR;
7606 }
7607
7608 int
7609 sys_listen (int s, int backlog)
7610 {
7611 if (winsock_lib == NULL)
7612 {
7613 errno = ENETDOWN;
7614 return SOCKET_ERROR;
7615 }
7616
7617 check_errno ();
7618 if (fd_info[s].flags & FILE_SOCKET)
7619 {
7620 int rc = pfn_listen (SOCK_HANDLE (s), backlog);
7621 if (rc == SOCKET_ERROR)
7622 set_errno ();
7623 else
7624 fd_info[s].flags |= FILE_LISTEN;
7625 return rc;
7626 }
7627 errno = ENOTSOCK;
7628 return SOCKET_ERROR;
7629 }
7630
7631 int
7632 sys_getsockname (int s, struct sockaddr * name, int * namelen)
7633 {
7634 if (winsock_lib == NULL)
7635 {
7636 errno = ENETDOWN;
7637 return SOCKET_ERROR;
7638 }
7639
7640 check_errno ();
7641 if (fd_info[s].flags & FILE_SOCKET)
7642 {
7643 int rc = pfn_getsockname (SOCK_HANDLE (s), name, namelen);
7644 if (rc == SOCKET_ERROR)
7645 set_errno ();
7646 return rc;
7647 }
7648 errno = ENOTSOCK;
7649 return SOCKET_ERROR;
7650 }
7651
7652 int
7653 sys_accept (int s, struct sockaddr * addr, int * addrlen)
7654 {
7655 if (winsock_lib == NULL)
7656 {
7657 errno = ENETDOWN;
7658 return -1;
7659 }
7660
7661 check_errno ();
7662 if (fd_info[s].flags & FILE_LISTEN)
7663 {
7664 SOCKET t = pfn_accept (SOCK_HANDLE (s), addr, addrlen);
7665 int fd = -1;
7666 if (t == INVALID_SOCKET)
7667 set_errno ();
7668 else
7669 fd = socket_to_fd (t);
7670
7671 if (fd >= 0)
7672 {
7673 fd_info[s].cp->status = STATUS_READ_ACKNOWLEDGED;
7674 ResetEvent (fd_info[s].cp->char_avail);
7675 }
7676 return fd;
7677 }
7678 errno = ENOTSOCK;
7679 return -1;
7680 }
7681
7682 int
7683 sys_recvfrom (int s, char * buf, int len, int flags,
7684 struct sockaddr * from, int * fromlen)
7685 {
7686 if (winsock_lib == NULL)
7687 {
7688 errno = ENETDOWN;
7689 return SOCKET_ERROR;
7690 }
7691
7692 check_errno ();
7693 if (fd_info[s].flags & FILE_SOCKET)
7694 {
7695 int rc = pfn_recvfrom (SOCK_HANDLE (s), buf, len, flags, from, fromlen);
7696 if (rc == SOCKET_ERROR)
7697 set_errno ();
7698 return rc;
7699 }
7700 errno = ENOTSOCK;
7701 return SOCKET_ERROR;
7702 }
7703
7704 int
7705 sys_sendto (int s, const char * buf, int len, int flags,
7706 const struct sockaddr * to, int tolen)
7707 {
7708 if (winsock_lib == NULL)
7709 {
7710 errno = ENETDOWN;
7711 return SOCKET_ERROR;
7712 }
7713
7714 check_errno ();
7715 if (fd_info[s].flags & FILE_SOCKET)
7716 {
7717 int rc = pfn_sendto (SOCK_HANDLE (s), buf, len, flags, to, tolen);
7718 if (rc == SOCKET_ERROR)
7719 set_errno ();
7720 return rc;
7721 }
7722 errno = ENOTSOCK;
7723 return SOCKET_ERROR;
7724 }
7725
7726 /* Windows does not have an fcntl function. Provide an implementation
7727 good enough for Emacs. */
7728 int
7729 fcntl (int s, int cmd, int options)
7730 {
7731 /* In the w32 Emacs port, fcntl (fd, F_DUPFD_CLOEXEC, fd1) is always
7732 invoked in a context where fd1 is closed and all descriptors less
7733 than fd1 are open, so sys_dup is an adequate implementation. */
7734 if (cmd == F_DUPFD_CLOEXEC)
7735 return sys_dup (s);
7736
7737 check_errno ();
7738 if (fd_info[s].flags & FILE_SOCKET)
7739 {
7740 if (winsock_lib == NULL)
7741 {
7742 errno = ENETDOWN;
7743 return -1;
7744 }
7745
7746 if (cmd == F_SETFL && options == O_NONBLOCK)
7747 {
7748 unsigned long nblock = 1;
7749 int rc = pfn_ioctlsocket (SOCK_HANDLE (s), FIONBIO, &nblock);
7750 if (rc == SOCKET_ERROR)
7751 set_errno ();
7752 /* Keep track of the fact that we set this to non-blocking. */
7753 fd_info[s].flags |= FILE_NDELAY;
7754 return rc;
7755 }
7756 else
7757 {
7758 errno = EINVAL;
7759 return SOCKET_ERROR;
7760 }
7761 }
7762 else if ((fd_info[s].flags & (FILE_PIPE | FILE_WRITE))
7763 == (FILE_PIPE | FILE_WRITE))
7764 {
7765 /* Force our writes to pipes be non-blocking. */
7766 if (cmd == F_SETFL && options == O_NONBLOCK)
7767 {
7768 HANDLE h = (HANDLE)_get_osfhandle (s);
7769 DWORD pipe_mode = PIPE_NOWAIT;
7770
7771 if (!SetNamedPipeHandleState (h, &pipe_mode, NULL, NULL))
7772 {
7773 DebPrint (("SetNamedPipeHandleState: %lu\n", GetLastError ()));
7774 return SOCKET_ERROR;
7775 }
7776 fd_info[s].flags |= FILE_NDELAY;
7777 return 0;
7778 }
7779 else
7780 {
7781 errno = EINVAL;
7782 return SOCKET_ERROR;
7783 }
7784 }
7785 errno = ENOTSOCK;
7786 return SOCKET_ERROR;
7787 }
7788
7789
7790 /* Shadow main io functions: we need to handle pipes and sockets more
7791 intelligently. */
7792
7793 int
7794 sys_close (int fd)
7795 {
7796 int rc;
7797
7798 if (fd < 0)
7799 {
7800 errno = EBADF;
7801 return -1;
7802 }
7803
7804 if (fd < MAXDESC && fd_info[fd].cp)
7805 {
7806 child_process * cp = fd_info[fd].cp;
7807
7808 fd_info[fd].cp = NULL;
7809
7810 if (CHILD_ACTIVE (cp))
7811 {
7812 /* if last descriptor to active child_process then cleanup */
7813 int i;
7814 for (i = 0; i < MAXDESC; i++)
7815 {
7816 if (i == fd)
7817 continue;
7818 if (fd_info[i].cp == cp)
7819 break;
7820 }
7821 if (i == MAXDESC)
7822 {
7823 if (fd_info[fd].flags & FILE_SOCKET)
7824 {
7825 if (winsock_lib == NULL) emacs_abort ();
7826
7827 pfn_shutdown (SOCK_HANDLE (fd), 2);
7828 rc = pfn_closesocket (SOCK_HANDLE (fd));
7829
7830 winsock_inuse--; /* count open sockets */
7831 }
7832 /* If the process handle is NULL, it's either a socket
7833 or serial connection, or a subprocess that was
7834 already reaped by reap_subprocess, but whose
7835 resources were not yet freed, because its output was
7836 not fully read yet by the time it was reaped. (This
7837 usually happens with async subprocesses whose output
7838 is being read by Emacs.) Otherwise, this process was
7839 not reaped yet, so we set its FD to a negative value
7840 to make sure sys_select will eventually get to
7841 calling the SIGCHLD handler for it, which will then
7842 invoke waitpid and reap_subprocess. */
7843 if (cp->procinfo.hProcess == NULL)
7844 delete_child (cp);
7845 else
7846 cp->fd = -1;
7847 }
7848 }
7849 }
7850
7851 if (fd >= 0 && fd < MAXDESC)
7852 fd_info[fd].flags = 0;
7853
7854 /* Note that sockets do not need special treatment here (at least on
7855 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
7856 closesocket is equivalent to CloseHandle, which is to be expected
7857 because socket handles are fully fledged kernel handles. */
7858 rc = _close (fd);
7859
7860 return rc;
7861 }
7862
7863 int
7864 sys_dup (int fd)
7865 {
7866 int new_fd;
7867
7868 new_fd = _dup (fd);
7869 if (new_fd >= 0 && new_fd < MAXDESC)
7870 {
7871 /* duplicate our internal info as well */
7872 fd_info[new_fd] = fd_info[fd];
7873 }
7874 return new_fd;
7875 }
7876
7877 int
7878 sys_dup2 (int src, int dst)
7879 {
7880 int rc;
7881
7882 if (dst < 0 || dst >= MAXDESC)
7883 {
7884 errno = EBADF;
7885 return -1;
7886 }
7887
7888 /* make sure we close the destination first if it's a pipe or socket */
7889 if (src != dst && fd_info[dst].flags != 0)
7890 sys_close (dst);
7891
7892 rc = _dup2 (src, dst);
7893 if (rc == 0)
7894 {
7895 /* duplicate our internal info as well */
7896 fd_info[dst] = fd_info[src];
7897 }
7898 return rc;
7899 }
7900
7901 int
7902 pipe2 (int * phandles, int pipe2_flags)
7903 {
7904 int rc;
7905 unsigned flags;
7906
7907 eassert (pipe2_flags == (O_BINARY | O_CLOEXEC));
7908
7909 /* make pipe handles non-inheritable; when we spawn a child, we
7910 replace the relevant handle with an inheritable one. Also put
7911 pipes into binary mode; we will do text mode translation ourselves
7912 if required. */
7913 rc = _pipe (phandles, 0, _O_NOINHERIT | _O_BINARY);
7914
7915 if (rc == 0)
7916 {
7917 /* Protect against overflow, since Windows can open more handles than
7918 our fd_info array has room for. */
7919 if (phandles[0] >= MAXDESC || phandles[1] >= MAXDESC)
7920 {
7921 _close (phandles[0]);
7922 _close (phandles[1]);
7923 errno = EMFILE;
7924 rc = -1;
7925 }
7926 else
7927 {
7928 flags = FILE_PIPE | FILE_READ | FILE_BINARY;
7929 fd_info[phandles[0]].flags = flags;
7930
7931 flags = FILE_PIPE | FILE_WRITE | FILE_BINARY;
7932 fd_info[phandles[1]].flags = flags;
7933 }
7934 }
7935
7936 return rc;
7937 }
7938
7939 /* Function to do blocking read of one byte, needed to implement
7940 select. It is only allowed on communication ports, sockets, or
7941 pipes. */
7942 int
7943 _sys_read_ahead (int fd)
7944 {
7945 child_process * cp;
7946 int rc;
7947
7948 if (fd < 0 || fd >= MAXDESC)
7949 return STATUS_READ_ERROR;
7950
7951 cp = fd_info[fd].cp;
7952
7953 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
7954 return STATUS_READ_ERROR;
7955
7956 if ((fd_info[fd].flags & (FILE_PIPE | FILE_SERIAL | FILE_SOCKET)) == 0
7957 || (fd_info[fd].flags & FILE_READ) == 0)
7958 {
7959 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd));
7960 emacs_abort ();
7961 }
7962
7963 cp->status = STATUS_READ_IN_PROGRESS;
7964
7965 if (fd_info[fd].flags & FILE_PIPE)
7966 {
7967 rc = _read (fd, &cp->chr, sizeof (char));
7968
7969 /* Give subprocess time to buffer some more output for us before
7970 reporting that input is available; we need this because Windows 95
7971 connects DOS programs to pipes by making the pipe appear to be
7972 the normal console stdout - as a result most DOS programs will
7973 write to stdout without buffering, ie. one character at a
7974 time. Even some W32 programs do this - "dir" in a command
7975 shell on NT is very slow if we don't do this. */
7976 if (rc > 0)
7977 {
7978 int wait = w32_pipe_read_delay;
7979
7980 if (wait > 0)
7981 Sleep (wait);
7982 else if (wait < 0)
7983 while (++wait <= 0)
7984 /* Yield remainder of our time slice, effectively giving a
7985 temporary priority boost to the child process. */
7986 Sleep (0);
7987 }
7988 }
7989 else if (fd_info[fd].flags & FILE_SERIAL)
7990 {
7991 HANDLE hnd = fd_info[fd].hnd;
7992 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
7993 COMMTIMEOUTS ct;
7994
7995 /* Configure timeouts for blocking read. */
7996 if (!GetCommTimeouts (hnd, &ct))
7997 {
7998 cp->status = STATUS_READ_ERROR;
7999 return STATUS_READ_ERROR;
8000 }
8001 ct.ReadIntervalTimeout = 0;
8002 ct.ReadTotalTimeoutMultiplier = 0;
8003 ct.ReadTotalTimeoutConstant = 0;
8004 if (!SetCommTimeouts (hnd, &ct))
8005 {
8006 cp->status = STATUS_READ_ERROR;
8007 return STATUS_READ_ERROR;
8008 }
8009
8010 if (!ReadFile (hnd, &cp->chr, sizeof (char), (DWORD*) &rc, ovl))
8011 {
8012 if (GetLastError () != ERROR_IO_PENDING)
8013 {
8014 cp->status = STATUS_READ_ERROR;
8015 return STATUS_READ_ERROR;
8016 }
8017 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
8018 {
8019 cp->status = STATUS_READ_ERROR;
8020 return STATUS_READ_ERROR;
8021 }
8022 }
8023 }
8024 else if (fd_info[fd].flags & FILE_SOCKET)
8025 {
8026 unsigned long nblock = 0;
8027 /* We always want this to block, so temporarily disable NDELAY. */
8028 if (fd_info[fd].flags & FILE_NDELAY)
8029 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
8030
8031 rc = pfn_recv (SOCK_HANDLE (fd), &cp->chr, sizeof (char), 0);
8032
8033 if (fd_info[fd].flags & FILE_NDELAY)
8034 {
8035 nblock = 1;
8036 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
8037 }
8038 }
8039
8040 if (rc == sizeof (char))
8041 cp->status = STATUS_READ_SUCCEEDED;
8042 else
8043 cp->status = STATUS_READ_FAILED;
8044
8045 return cp->status;
8046 }
8047
8048 int
8049 _sys_wait_accept (int fd)
8050 {
8051 HANDLE hEv;
8052 child_process * cp;
8053 int rc;
8054
8055 if (fd < 0 || fd >= MAXDESC)
8056 return STATUS_READ_ERROR;
8057
8058 cp = fd_info[fd].cp;
8059
8060 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
8061 return STATUS_READ_ERROR;
8062
8063 cp->status = STATUS_READ_FAILED;
8064
8065 hEv = pfn_WSACreateEvent ();
8066 rc = pfn_WSAEventSelect (SOCK_HANDLE (fd), hEv, FD_ACCEPT);
8067 if (rc != SOCKET_ERROR)
8068 {
8069 do {
8070 rc = WaitForSingleObject (hEv, 500);
8071 Sleep (5);
8072 } while (rc == WAIT_TIMEOUT
8073 && cp->status != STATUS_READ_ERROR
8074 && cp->char_avail);
8075 pfn_WSAEventSelect (SOCK_HANDLE (fd), NULL, 0);
8076 if (rc == WAIT_OBJECT_0)
8077 cp->status = STATUS_READ_SUCCEEDED;
8078 }
8079 pfn_WSACloseEvent (hEv);
8080
8081 return cp->status;
8082 }
8083
8084 int
8085 sys_read (int fd, char * buffer, unsigned int count)
8086 {
8087 int nchars;
8088 int to_read;
8089 DWORD waiting;
8090 char * orig_buffer = buffer;
8091
8092 if (fd < 0)
8093 {
8094 errno = EBADF;
8095 return -1;
8096 }
8097
8098 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
8099 {
8100 child_process *cp = fd_info[fd].cp;
8101
8102 if ((fd_info[fd].flags & FILE_READ) == 0)
8103 {
8104 errno = EBADF;
8105 return -1;
8106 }
8107
8108 nchars = 0;
8109
8110 /* re-read CR carried over from last read */
8111 if (fd_info[fd].flags & FILE_LAST_CR)
8112 {
8113 if (fd_info[fd].flags & FILE_BINARY) emacs_abort ();
8114 *buffer++ = 0x0d;
8115 count--;
8116 nchars++;
8117 fd_info[fd].flags &= ~FILE_LAST_CR;
8118 }
8119
8120 /* presence of a child_process structure means we are operating in
8121 non-blocking mode - otherwise we just call _read directly.
8122 Note that the child_process structure might be missing because
8123 reap_subprocess has been called; in this case the pipe is
8124 already broken, so calling _read on it is okay. */
8125 if (cp)
8126 {
8127 int current_status = cp->status;
8128
8129 switch (current_status)
8130 {
8131 case STATUS_READ_FAILED:
8132 case STATUS_READ_ERROR:
8133 /* report normal EOF if nothing in buffer */
8134 if (nchars <= 0)
8135 fd_info[fd].flags |= FILE_AT_EOF;
8136 return nchars;
8137
8138 case STATUS_READ_READY:
8139 case STATUS_READ_IN_PROGRESS:
8140 DebPrint (("sys_read called when read is in progress\n"));
8141 errno = EWOULDBLOCK;
8142 return -1;
8143
8144 case STATUS_READ_SUCCEEDED:
8145 /* consume read-ahead char */
8146 *buffer++ = cp->chr;
8147 count--;
8148 nchars++;
8149 cp->status = STATUS_READ_ACKNOWLEDGED;
8150 ResetEvent (cp->char_avail);
8151
8152 case STATUS_READ_ACKNOWLEDGED:
8153 break;
8154
8155 default:
8156 DebPrint (("sys_read: bad status %d\n", current_status));
8157 errno = EBADF;
8158 return -1;
8159 }
8160
8161 if (fd_info[fd].flags & FILE_PIPE)
8162 {
8163 PeekNamedPipe ((HANDLE) _get_osfhandle (fd), NULL, 0, NULL, &waiting, NULL);
8164 to_read = min (waiting, (DWORD) count);
8165
8166 if (to_read > 0)
8167 nchars += _read (fd, buffer, to_read);
8168 }
8169 else if (fd_info[fd].flags & FILE_SERIAL)
8170 {
8171 HANDLE hnd = fd_info[fd].hnd;
8172 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
8173 int rc = 0;
8174 COMMTIMEOUTS ct;
8175
8176 if (count > 0)
8177 {
8178 /* Configure timeouts for non-blocking read. */
8179 if (!GetCommTimeouts (hnd, &ct))
8180 {
8181 errno = EIO;
8182 return -1;
8183 }
8184 ct.ReadIntervalTimeout = MAXDWORD;
8185 ct.ReadTotalTimeoutMultiplier = 0;
8186 ct.ReadTotalTimeoutConstant = 0;
8187 if (!SetCommTimeouts (hnd, &ct))
8188 {
8189 errno = EIO;
8190 return -1;
8191 }
8192
8193 if (!ResetEvent (ovl->hEvent))
8194 {
8195 errno = EIO;
8196 return -1;
8197 }
8198 if (!ReadFile (hnd, buffer, count, (DWORD*) &rc, ovl))
8199 {
8200 if (GetLastError () != ERROR_IO_PENDING)
8201 {
8202 errno = EIO;
8203 return -1;
8204 }
8205 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
8206 {
8207 errno = EIO;
8208 return -1;
8209 }
8210 }
8211 nchars += rc;
8212 }
8213 }
8214 else /* FILE_SOCKET */
8215 {
8216 if (winsock_lib == NULL) emacs_abort ();
8217
8218 /* do the equivalent of a non-blocking read */
8219 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONREAD, &waiting);
8220 if (waiting == 0 && nchars == 0)
8221 {
8222 errno = EWOULDBLOCK;
8223 return -1;
8224 }
8225
8226 if (waiting)
8227 {
8228 /* always use binary mode for sockets */
8229 int res = pfn_recv (SOCK_HANDLE (fd), buffer, count, 0);
8230 if (res == SOCKET_ERROR)
8231 {
8232 DebPrint (("sys_read.recv failed with error %d on socket %ld\n",
8233 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
8234 set_errno ();
8235 return -1;
8236 }
8237 nchars += res;
8238 }
8239 }
8240 }
8241 else
8242 {
8243 int nread = _read (fd, buffer, count);
8244 if (nread >= 0)
8245 nchars += nread;
8246 else if (nchars == 0)
8247 nchars = nread;
8248 }
8249
8250 if (nchars <= 0)
8251 fd_info[fd].flags |= FILE_AT_EOF;
8252 /* Perform text mode translation if required. */
8253 else if ((fd_info[fd].flags & FILE_BINARY) == 0)
8254 {
8255 nchars = crlf_to_lf (nchars, orig_buffer);
8256 /* If buffer contains only CR, return that. To be absolutely
8257 sure we should attempt to read the next char, but in
8258 practice a CR to be followed by LF would not appear by
8259 itself in the buffer. */
8260 if (nchars > 1 && orig_buffer[nchars - 1] == 0x0d)
8261 {
8262 fd_info[fd].flags |= FILE_LAST_CR;
8263 nchars--;
8264 }
8265 }
8266 }
8267 else
8268 nchars = _read (fd, buffer, count);
8269
8270 return nchars;
8271 }
8272
8273 /* From w32xfns.c */
8274 extern HANDLE interrupt_handle;
8275
8276 int
8277 sys_write (int fd, const void * buffer, unsigned int count)
8278 {
8279 int nchars;
8280 USE_SAFE_ALLOCA;
8281
8282 if (fd < 0)
8283 {
8284 errno = EBADF;
8285 return -1;
8286 }
8287
8288 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
8289 {
8290 if ((fd_info[fd].flags & FILE_WRITE) == 0)
8291 {
8292 errno = EBADF;
8293 return -1;
8294 }
8295
8296 /* Perform text mode translation if required. */
8297 if ((fd_info[fd].flags & FILE_BINARY) == 0)
8298 {
8299 char * tmpbuf;
8300 const unsigned char * src = buffer;
8301 unsigned char * dst;
8302 int nbytes = count;
8303
8304 SAFE_NALLOCA (tmpbuf, 2, count);
8305 dst = tmpbuf;
8306
8307 while (1)
8308 {
8309 unsigned char *next;
8310 /* Copy next line or remaining bytes. */
8311 next = _memccpy (dst, src, '\n', nbytes);
8312 if (next)
8313 {
8314 /* Copied one line ending with '\n'. */
8315 int copied = next - dst;
8316 nbytes -= copied;
8317 src += copied;
8318 /* Insert '\r' before '\n'. */
8319 next[-1] = '\r';
8320 next[0] = '\n';
8321 dst = next + 1;
8322 count++;
8323 }
8324 else
8325 /* Copied remaining partial line -> now finished. */
8326 break;
8327 }
8328 buffer = tmpbuf;
8329 }
8330 }
8331
8332 if (fd < MAXDESC && fd_info[fd].flags & FILE_SERIAL)
8333 {
8334 HANDLE hnd = (HANDLE) _get_osfhandle (fd);
8335 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_write;
8336 HANDLE wait_hnd[2] = { interrupt_handle, ovl->hEvent };
8337 DWORD active = 0;
8338
8339 /* This is async (a.k.a. "overlapped") I/O, so the return value
8340 of FALSE from WriteFile means either an error or the output
8341 will be completed asynchronously (ERROR_IO_PENDING). */
8342 if (!WriteFile (hnd, buffer, count, (DWORD*) &nchars, ovl))
8343 {
8344 if (GetLastError () != ERROR_IO_PENDING)
8345 {
8346 errno = EIO;
8347 nchars = -1;
8348 }
8349 else
8350 {
8351 /* Wait for the write to complete, and watch C-g while
8352 at that. */
8353 if (detect_input_pending ())
8354 active = MsgWaitForMultipleObjects (2, wait_hnd, FALSE,
8355 INFINITE, QS_ALLINPUT);
8356 else
8357 active = WaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE);
8358 switch (active)
8359 {
8360 case WAIT_OBJECT_0:
8361 /* User pressed C-g, cancel write, then leave.
8362 Don't bother cleaning up as we may only get stuck
8363 in buggy drivers. */
8364 PurgeComm (hnd, PURGE_TXABORT | PURGE_TXCLEAR);
8365 CancelIo (hnd);
8366 errno = EIO; /* Why not EINTR? */
8367 nchars = -1;
8368 break;
8369 case WAIT_OBJECT_0 + 1:
8370 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &nchars, TRUE))
8371 {
8372 errno = EIO;
8373 nchars = -1;
8374 }
8375 break;
8376 }
8377 }
8378 }
8379 }
8380 else if (fd < MAXDESC && fd_info[fd].flags & FILE_SOCKET)
8381 {
8382 unsigned long nblock = 0;
8383 if (winsock_lib == NULL) emacs_abort ();
8384
8385 /* TODO: implement select() properly so non-blocking I/O works. */
8386 /* For now, make sure the write blocks. */
8387 if (fd_info[fd].flags & FILE_NDELAY)
8388 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
8389
8390 nchars = pfn_send (SOCK_HANDLE (fd), buffer, count, 0);
8391
8392 /* Set the socket back to non-blocking if it was before,
8393 for other operations that support it. */
8394 if (fd_info[fd].flags & FILE_NDELAY)
8395 {
8396 nblock = 1;
8397 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
8398 }
8399
8400 if (nchars == SOCKET_ERROR)
8401 {
8402 DebPrint (("sys_write.send failed with error %d on socket %ld\n",
8403 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
8404 set_errno ();
8405 }
8406 }
8407 else
8408 {
8409 /* Some networked filesystems don't like too large writes, so
8410 break them into smaller chunks. See the Comments section of
8411 the MSDN documentation of WriteFile for details behind the
8412 choice of the value of CHUNK below. See also the thread
8413 http://thread.gmane.org/gmane.comp.version-control.git/145294
8414 in the git mailing list. */
8415 const unsigned char *p = buffer;
8416 const unsigned chunk = 30 * 1024 * 1024;
8417
8418 nchars = 0;
8419 while (count > 0)
8420 {
8421 unsigned this_chunk = count < chunk ? count : chunk;
8422 int n = _write (fd, p, this_chunk);
8423
8424 nchars += n;
8425 if (n < 0)
8426 {
8427 /* When there's no buffer space in a pipe that is in the
8428 non-blocking mode, _write returns ENOSPC. We return
8429 EAGAIN instead, which should trigger the logic in
8430 send_process that enters waiting loop and calls
8431 wait_reading_process_output to allow process input to
8432 be accepted during the wait. Those calls to
8433 wait_reading_process_output allow sys_select to
8434 notice when process input becomes available, thus
8435 avoiding deadlock whereby each side of the pipe is
8436 blocked on write, waiting for the other party to read
8437 its end of the pipe. */
8438 if (errno == ENOSPC
8439 && fd < MAXDESC
8440 && ((fd_info[fd].flags & (FILE_PIPE | FILE_NDELAY))
8441 == (FILE_PIPE | FILE_NDELAY)))
8442 errno = EAGAIN;
8443 nchars = n;
8444 break;
8445 }
8446 else if (n < this_chunk)
8447 break;
8448 count -= n;
8449 p += n;
8450 }
8451 }
8452
8453 SAFE_FREE ();
8454 return nchars;
8455 }
8456
8457 \f
8458 /* Emulation of SIOCGIFCONF and getifaddrs, see process.c. */
8459
8460 extern Lisp_Object conv_sockaddr_to_lisp (struct sockaddr *, int);
8461
8462 /* Return information about network interface IFNAME, or about all
8463 interfaces (if IFNAME is nil). */
8464 static Lisp_Object
8465 network_interface_get_info (Lisp_Object ifname)
8466 {
8467 ULONG ainfo_len = sizeof (IP_ADAPTER_INFO);
8468 IP_ADAPTER_INFO *adapter, *ainfo = xmalloc (ainfo_len);
8469 DWORD retval = get_adapters_info (ainfo, &ainfo_len);
8470 Lisp_Object res = Qnil;
8471
8472 if (retval == ERROR_BUFFER_OVERFLOW)
8473 {
8474 ainfo = xrealloc (ainfo, ainfo_len);
8475 retval = get_adapters_info (ainfo, &ainfo_len);
8476 }
8477
8478 if (retval == ERROR_SUCCESS)
8479 {
8480 int eth_count = 0, tr_count = 0, fddi_count = 0, ppp_count = 0;
8481 int sl_count = 0, wlan_count = 0, lo_count = 0, ifx_count = 0;
8482 int if_num;
8483 struct sockaddr_in sa;
8484
8485 /* For the below, we need some winsock functions, so make sure
8486 the winsock DLL is loaded. If we cannot successfully load
8487 it, they will have no use of the information we provide,
8488 anyway, so punt. */
8489 if (!winsock_lib && !init_winsock (1))
8490 goto done;
8491
8492 for (adapter = ainfo; adapter; adapter = adapter->Next)
8493 {
8494 char namebuf[MAX_ADAPTER_NAME_LENGTH + 4];
8495 u_long ip_addr;
8496 /* Present Unix-compatible interface names, instead of the
8497 Windows names, which are really GUIDs not readable by
8498 humans. */
8499 static const char *ifmt[] = {
8500 "eth%d", "tr%d", "fddi%d", "ppp%d", "sl%d", "wlan%d",
8501 "lo", "ifx%d"
8502 };
8503 enum {
8504 NONE = -1,
8505 ETHERNET = 0,
8506 TOKENRING = 1,
8507 FDDI = 2,
8508 PPP = 3,
8509 SLIP = 4,
8510 WLAN = 5,
8511 LOOPBACK = 6,
8512 OTHER_IF = 7
8513 } ifmt_idx;
8514
8515 switch (adapter->Type)
8516 {
8517 case MIB_IF_TYPE_ETHERNET:
8518 /* Windows before Vista reports wireless adapters as
8519 Ethernet. Work around by looking at the Description
8520 string. */
8521 if (strstr (adapter->Description, "Wireless "))
8522 {
8523 ifmt_idx = WLAN;
8524 if_num = wlan_count++;
8525 }
8526 else
8527 {
8528 ifmt_idx = ETHERNET;
8529 if_num = eth_count++;
8530 }
8531 break;
8532 case MIB_IF_TYPE_TOKENRING:
8533 ifmt_idx = TOKENRING;
8534 if_num = tr_count++;
8535 break;
8536 case MIB_IF_TYPE_FDDI:
8537 ifmt_idx = FDDI;
8538 if_num = fddi_count++;
8539 break;
8540 case MIB_IF_TYPE_PPP:
8541 ifmt_idx = PPP;
8542 if_num = ppp_count++;
8543 break;
8544 case MIB_IF_TYPE_SLIP:
8545 ifmt_idx = SLIP;
8546 if_num = sl_count++;
8547 break;
8548 case IF_TYPE_IEEE80211:
8549 ifmt_idx = WLAN;
8550 if_num = wlan_count++;
8551 break;
8552 case MIB_IF_TYPE_LOOPBACK:
8553 if (lo_count < 0)
8554 {
8555 ifmt_idx = LOOPBACK;
8556 if_num = lo_count++;
8557 }
8558 else
8559 ifmt_idx = NONE;
8560 break;
8561 default:
8562 ifmt_idx = OTHER_IF;
8563 if_num = ifx_count++;
8564 break;
8565 }
8566 if (ifmt_idx == NONE)
8567 continue;
8568 sprintf (namebuf, ifmt[ifmt_idx], if_num);
8569
8570 sa.sin_family = AF_INET;
8571 ip_addr = sys_inet_addr (adapter->IpAddressList.IpAddress.String);
8572 if (ip_addr == INADDR_NONE)
8573 {
8574 /* Bogus address, skip this interface. */
8575 continue;
8576 }
8577 sa.sin_addr.s_addr = ip_addr;
8578 sa.sin_port = 0;
8579 if (NILP (ifname))
8580 res = Fcons (Fcons (build_string (namebuf),
8581 conv_sockaddr_to_lisp ((struct sockaddr*) &sa,
8582 sizeof (struct sockaddr))),
8583 res);
8584 else if (strcmp (namebuf, SSDATA (ifname)) == 0)
8585 {
8586 Lisp_Object hwaddr = Fmake_vector (make_number (6), Qnil);
8587 register struct Lisp_Vector *p = XVECTOR (hwaddr);
8588 Lisp_Object flags = Qnil;
8589 int n;
8590 u_long net_mask;
8591
8592 /* Flags. We guess most of them by type, since the
8593 Windows flags are different and hard to get by. */
8594 flags = Fcons (intern ("up"), flags);
8595 if (ifmt_idx == ETHERNET || ifmt_idx == WLAN)
8596 {
8597 flags = Fcons (intern ("broadcast"), flags);
8598 flags = Fcons (intern ("multicast"), flags);
8599 }
8600 flags = Fcons (intern ("running"), flags);
8601 if (ifmt_idx == PPP)
8602 {
8603 flags = Fcons (intern ("pointopoint"), flags);
8604 flags = Fcons (intern ("noarp"), flags);
8605 }
8606 if (adapter->HaveWins)
8607 flags = Fcons (intern ("WINS"), flags);
8608 if (adapter->DhcpEnabled)
8609 flags = Fcons (intern ("dynamic"), flags);
8610
8611 res = Fcons (flags, res);
8612
8613 /* Hardware address and its family. */
8614 for (n = 0; n < adapter->AddressLength; n++)
8615 p->contents[n] = make_number ((int) adapter->Address[n]);
8616 /* Windows does not support AF_LINK or AF_PACKET family
8617 of addresses. Use an arbitrary family number that is
8618 identical to what GNU/Linux returns. */
8619 res = Fcons (Fcons (make_number (1), hwaddr), res);
8620
8621 /* Network mask. */
8622 sa.sin_family = AF_INET;
8623 net_mask = sys_inet_addr (adapter->IpAddressList.IpMask.String);
8624 if (net_mask != INADDR_NONE)
8625 {
8626 sa.sin_addr.s_addr = net_mask;
8627 sa.sin_port = 0;
8628 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
8629 sizeof (struct sockaddr)),
8630 res);
8631 }
8632 else
8633 res = Fcons (Qnil, res);
8634
8635 sa.sin_family = AF_INET;
8636 if (ip_addr != INADDR_NONE)
8637 {
8638 /* Broadcast address is only reported by
8639 GetAdaptersAddresses, which is of limited
8640 availability. Generate it on our own. */
8641 u_long bcast_addr = (ip_addr & net_mask) | ~net_mask;
8642
8643 sa.sin_addr.s_addr = bcast_addr;
8644 sa.sin_port = 0;
8645 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
8646 sizeof (struct sockaddr)),
8647 res);
8648
8649 /* IP address. */
8650 sa.sin_addr.s_addr = ip_addr;
8651 sa.sin_port = 0;
8652 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
8653 sizeof (struct sockaddr)),
8654 res);
8655 }
8656 else
8657 res = Fcons (Qnil, Fcons (Qnil, res));
8658 }
8659 }
8660 /* GetAdaptersInfo is documented to not report loopback
8661 interfaces, so we generate one out of thin air. */
8662 if (!lo_count)
8663 {
8664 sa.sin_family = AF_INET;
8665 sa.sin_port = 0;
8666 if (NILP (ifname))
8667 {
8668 sa.sin_addr.s_addr = sys_inet_addr ("127.0.0.1");
8669 res = Fcons (Fcons (build_string ("lo"),
8670 conv_sockaddr_to_lisp ((struct sockaddr*) &sa,
8671 sizeof (struct sockaddr))),
8672 res);
8673 }
8674 else if (strcmp (SSDATA (ifname), "lo") == 0)
8675 {
8676 res = Fcons (Fcons (intern ("running"),
8677 Fcons (intern ("loopback"),
8678 Fcons (intern ("up"), Qnil))), Qnil);
8679 /* 772 is what 3 different GNU/Linux systems report for
8680 the loopback interface. */
8681 res = Fcons (Fcons (make_number (772),
8682 Fmake_vector (make_number (6),
8683 make_number (0))),
8684 res);
8685 sa.sin_addr.s_addr = sys_inet_addr ("255.0.0.0");
8686 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
8687 sizeof (struct sockaddr)),
8688 res);
8689 sa.sin_addr.s_addr = sys_inet_addr ("0.0.0.0");
8690 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
8691 sizeof (struct sockaddr)),
8692 res);
8693 sa.sin_addr.s_addr = sys_inet_addr ("127.0.0.1");
8694 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
8695 sizeof (struct sockaddr)),
8696 res);
8697 }
8698
8699 }
8700 }
8701
8702 done:
8703 xfree (ainfo);
8704 return res;
8705 }
8706
8707 Lisp_Object
8708 network_interface_list (void)
8709 {
8710 return network_interface_get_info (Qnil);
8711 }
8712
8713 Lisp_Object
8714 network_interface_info (Lisp_Object ifname)
8715 {
8716 CHECK_STRING (ifname);
8717 return network_interface_get_info (ifname);
8718 }
8719
8720 \f
8721 /* The Windows CRT functions are "optimized for speed", so they don't
8722 check for timezone and DST changes if they were last called less
8723 than 1 minute ago (see http://support.microsoft.com/kb/821231). So
8724 all Emacs features that repeatedly call time functions (e.g.,
8725 display-time) are in real danger of missing timezone and DST
8726 changes. Calling tzset before each localtime call fixes that. */
8727 struct tm *
8728 sys_localtime (const time_t *t)
8729 {
8730 tzset ();
8731 return localtime (t);
8732 }
8733
8734
8735 \f
8736 /* Try loading LIBRARY_ID from the file(s) specified in
8737 Vdynamic_library_alist. If the library is loaded successfully,
8738 return the handle of the DLL, and record the filename in the
8739 property :loaded-from of LIBRARY_ID. If the library could not be
8740 found, or when it was already loaded (because the handle is not
8741 recorded anywhere, and so is lost after use), return NULL.
8742
8743 We could also save the handle in :loaded-from, but currently
8744 there's no use case for it. */
8745 HMODULE
8746 w32_delayed_load (Lisp_Object library_id)
8747 {
8748 HMODULE dll_handle = NULL;
8749
8750 CHECK_SYMBOL (library_id);
8751
8752 if (CONSP (Vdynamic_library_alist)
8753 && NILP (Fassq (library_id, Vlibrary_cache)))
8754 {
8755 Lisp_Object found = Qnil;
8756 Lisp_Object dlls = Fassq (library_id, Vdynamic_library_alist);
8757
8758 if (CONSP (dlls))
8759 for (dlls = XCDR (dlls); CONSP (dlls); dlls = XCDR (dlls))
8760 {
8761 Lisp_Object dll = XCAR (dlls);
8762 char name[MAX_UTF8_PATH];
8763 DWORD res = -1;
8764
8765 CHECK_STRING (dll);
8766 dll = ENCODE_FILE (dll);
8767 if (w32_unicode_filenames)
8768 {
8769 wchar_t name_w[MAX_PATH];
8770
8771 filename_to_utf16 (SSDATA (dll), name_w);
8772 dll_handle = LoadLibraryW (name_w);
8773 if (dll_handle)
8774 {
8775 res = GetModuleFileNameW (dll_handle, name_w,
8776 sizeof (name_w));
8777 if (res > 0)
8778 filename_from_utf16 (name_w, name);
8779 }
8780 }
8781 else
8782 {
8783 char name_a[MAX_PATH];
8784
8785 filename_to_ansi (SSDATA (dll), name_a);
8786 dll_handle = LoadLibraryA (name_a);
8787 if (dll_handle)
8788 {
8789 res = GetModuleFileNameA (dll_handle, name_a,
8790 sizeof (name_a));
8791 if (res > 0)
8792 filename_from_ansi (name_a, name);
8793 }
8794 }
8795 if (dll_handle)
8796 {
8797 ptrdiff_t len = strlen (name);
8798 found = Fcons (dll,
8799 (res > 0)
8800 /* Possibly truncated */
8801 ? make_specified_string (name, -1, len, 1)
8802 : Qnil);
8803 /* This prevents thread start and end notifications
8804 from being sent to the DLL, for every thread we
8805 start. We don't need those notifications because
8806 threads we create never use any of these DLLs, only
8807 the main thread uses them. This is supposed to
8808 speed up thread creation. */
8809 DisableThreadLibraryCalls (dll_handle);
8810 break;
8811 }
8812 }
8813
8814 Fput (library_id, QCloaded_from, found);
8815 }
8816
8817 return dll_handle;
8818 }
8819
8820 \f
8821 void
8822 check_windows_init_file (void)
8823 {
8824 /* A common indication that Emacs is not installed properly is when
8825 it cannot find the Windows installation file. If this file does
8826 not exist in the expected place, tell the user. */
8827
8828 if (!noninteractive && !inhibit_window_system
8829 /* Vload_path is not yet initialized when we are loading
8830 loadup.el. */
8831 && NILP (Vpurify_flag))
8832 {
8833 Lisp_Object init_file;
8834 int fd;
8835
8836 /* Implementation note: this function runs early during Emacs
8837 startup, before startup.el is run. So Vload_path is still in
8838 its initial unibyte form, but it holds UTF-8 encoded file
8839 names, since init_callproc was already called. So we do not
8840 need to ENCODE_FILE here, but we do need to convert the file
8841 names from UTF-8 to ANSI. */
8842 init_file = build_string ("term/w32-win");
8843 fd = openp (Vload_path, init_file, Fget_load_suffixes (), NULL, Qnil, 0);
8844 if (fd < 0)
8845 {
8846 Lisp_Object load_path_print = Fprin1_to_string (Vload_path, Qnil);
8847 char *init_file_name = SDATA (init_file);
8848 char *load_path = SDATA (load_path_print);
8849 char *buffer = alloca (1024
8850 + strlen (init_file_name)
8851 + strlen (load_path));
8852 char *msg = buffer;
8853 int needed;
8854
8855 sprintf (buffer,
8856 "The Emacs Windows initialization file \"%s.el\" "
8857 "could not be found in your Emacs installation. "
8858 "Emacs checked the following directories for this file:\n"
8859 "\n%s\n\n"
8860 "When Emacs cannot find this file, it usually means that it "
8861 "was not installed properly, or its distribution file was "
8862 "not unpacked properly.\nSee the README.W32 file in the "
8863 "top-level Emacs directory for more information.",
8864 init_file_name, load_path);
8865 needed = pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, buffer,
8866 -1, NULL, 0);
8867 if (needed > 0)
8868 {
8869 wchar_t *msg_w = alloca ((needed + 1) * sizeof (wchar_t));
8870
8871 pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, buffer, -1,
8872 msg_w, needed);
8873 needed = pWideCharToMultiByte (CP_ACP, 0, msg_w, -1,
8874 NULL, 0, NULL, NULL);
8875 if (needed > 0)
8876 {
8877 char *msg_a = alloca (needed + 1);
8878
8879 pWideCharToMultiByte (CP_ACP, 0, msg_w, -1, msg_a, needed,
8880 NULL, NULL);
8881 msg = msg_a;
8882 }
8883 }
8884 MessageBox (NULL,
8885 msg,
8886 "Emacs Abort Dialog",
8887 MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
8888 /* Use the low-level system abort. */
8889 abort ();
8890 }
8891 else
8892 {
8893 _close (fd);
8894 }
8895 }
8896 }
8897
8898 void
8899 term_ntproc (int ignored)
8900 {
8901 (void)ignored;
8902
8903 term_timers ();
8904
8905 /* shutdown the socket interface if necessary */
8906 term_winsock ();
8907
8908 term_w32select ();
8909 }
8910
8911 void
8912 init_ntproc (int dumping)
8913 {
8914 sigset_t initial_mask = 0;
8915
8916 /* Initialize the socket interface now if available and requested by
8917 the user by defining PRELOAD_WINSOCK; otherwise loading will be
8918 delayed until open-network-stream is called (w32-has-winsock can
8919 also be used to dynamically load or reload winsock).
8920
8921 Conveniently, init_environment is called before us, so
8922 PRELOAD_WINSOCK can be set in the registry. */
8923
8924 /* Always initialize this correctly. */
8925 winsock_lib = NULL;
8926
8927 if (getenv ("PRELOAD_WINSOCK") != NULL)
8928 init_winsock (TRUE);
8929
8930 /* Initial preparation for subprocess support: replace our standard
8931 handles with non-inheritable versions. */
8932 {
8933 HANDLE parent;
8934 HANDLE stdin_save = INVALID_HANDLE_VALUE;
8935 HANDLE stdout_save = INVALID_HANDLE_VALUE;
8936 HANDLE stderr_save = INVALID_HANDLE_VALUE;
8937
8938 parent = GetCurrentProcess ();
8939
8940 /* ignore errors when duplicating and closing; typically the
8941 handles will be invalid when running as a gui program. */
8942 DuplicateHandle (parent,
8943 GetStdHandle (STD_INPUT_HANDLE),
8944 parent,
8945 &stdin_save,
8946 0,
8947 FALSE,
8948 DUPLICATE_SAME_ACCESS);
8949
8950 DuplicateHandle (parent,
8951 GetStdHandle (STD_OUTPUT_HANDLE),
8952 parent,
8953 &stdout_save,
8954 0,
8955 FALSE,
8956 DUPLICATE_SAME_ACCESS);
8957
8958 DuplicateHandle (parent,
8959 GetStdHandle (STD_ERROR_HANDLE),
8960 parent,
8961 &stderr_save,
8962 0,
8963 FALSE,
8964 DUPLICATE_SAME_ACCESS);
8965
8966 fclose (stdin);
8967 fclose (stdout);
8968 fclose (stderr);
8969
8970 if (stdin_save != INVALID_HANDLE_VALUE)
8971 _open_osfhandle ((intptr_t) stdin_save, O_TEXT);
8972 else
8973 _open ("nul", O_TEXT | O_NOINHERIT | O_RDONLY);
8974 _fdopen (0, "r");
8975
8976 if (stdout_save != INVALID_HANDLE_VALUE)
8977 _open_osfhandle ((intptr_t) stdout_save, O_TEXT);
8978 else
8979 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
8980 _fdopen (1, "w");
8981
8982 if (stderr_save != INVALID_HANDLE_VALUE)
8983 _open_osfhandle ((intptr_t) stderr_save, O_TEXT);
8984 else
8985 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
8986 _fdopen (2, "w");
8987 }
8988
8989 /* unfortunately, atexit depends on implementation of malloc */
8990 /* atexit (term_ntproc); */
8991 if (!dumping)
8992 {
8993 /* Make sure we start with all signals unblocked. */
8994 sigprocmask (SIG_SETMASK, &initial_mask, NULL);
8995 signal (SIGABRT, term_ntproc);
8996 }
8997 init_timers ();
8998
8999 /* determine which drives are fixed, for GetCachedVolumeInformation */
9000 {
9001 /* GetDriveType must have trailing backslash. */
9002 char drive[] = "A:\\";
9003
9004 /* Loop over all possible drive letters */
9005 while (*drive <= 'Z')
9006 {
9007 /* Record if this drive letter refers to a fixed drive. */
9008 fixed_drives[DRIVE_INDEX (*drive)] =
9009 (GetDriveType (drive) == DRIVE_FIXED);
9010
9011 (*drive)++;
9012 }
9013
9014 /* Reset the volume info cache. */
9015 volume_cache = NULL;
9016 }
9017 }
9018
9019 /*
9020 shutdown_handler ensures that buffers' autosave files are
9021 up to date when the user logs off, or the system shuts down.
9022 */
9023 static BOOL WINAPI
9024 shutdown_handler (DWORD type)
9025 {
9026 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
9027 if (type == CTRL_CLOSE_EVENT /* User closes console window. */
9028 || type == CTRL_LOGOFF_EVENT /* User logs off. */
9029 || type == CTRL_SHUTDOWN_EVENT) /* User shutsdown. */
9030 {
9031 /* Shut down cleanly, making sure autosave files are up to date. */
9032 shut_down_emacs (0, Qnil);
9033 }
9034
9035 /* Allow other handlers to handle this signal. */
9036 return FALSE;
9037 }
9038
9039 /* On Windows 9X, load UNICOWS.DLL and return its handle, or die. On
9040 NT, return a handle to GDI32.DLL. */
9041 HANDLE
9042 maybe_load_unicows_dll (void)
9043 {
9044 if (os_subtype == OS_9X)
9045 {
9046 HANDLE ret = LoadLibrary ("Unicows.dll");
9047 if (ret)
9048 {
9049 /* These two functions are present on Windows 9X as stubs
9050 that always fail. We need the real implementations from
9051 UNICOWS.DLL, so we must call these functions through
9052 pointers, and assign the correct addresses to these
9053 pointers at program startup (see emacs.c, which calls
9054 this function early on). */
9055 pMultiByteToWideChar = GetProcAddress (ret, "MultiByteToWideChar");
9056 pWideCharToMultiByte = GetProcAddress (ret, "WideCharToMultiByte");
9057 return ret;
9058 }
9059 else
9060 {
9061 int button;
9062
9063 button = MessageBox (NULL,
9064 "Emacs cannot load the UNICOWS.DLL library.\n"
9065 "This library is essential for using Emacs\n"
9066 "on this system. You need to install it.\n\n"
9067 "Emacs will exit when you click OK.",
9068 "Emacs cannot load UNICOWS.DLL",
9069 MB_ICONERROR | MB_TASKMODAL
9070 | MB_SETFOREGROUND | MB_OK);
9071 switch (button)
9072 {
9073 case IDOK:
9074 default:
9075 exit (1);
9076 }
9077 }
9078 }
9079 else
9080 {
9081 /* On NT family of Windows, these two functions are always
9082 linked in, so we just assign their addresses to the 2
9083 pointers; no need for the LoadLibrary dance. */
9084 pMultiByteToWideChar = MultiByteToWideChar;
9085 pWideCharToMultiByte = WideCharToMultiByte;
9086 return LoadLibrary ("Gdi32.dll");
9087 }
9088 }
9089
9090 /*
9091 globals_of_w32 is used to initialize those global variables that
9092 must always be initialized on startup even when the global variable
9093 initialized is non zero (see the function main in emacs.c).
9094 */
9095 void
9096 globals_of_w32 (void)
9097 {
9098 HMODULE kernel32 = GetModuleHandle ("kernel32.dll");
9099
9100 get_process_times_fn = (GetProcessTimes_Proc)
9101 GetProcAddress (kernel32, "GetProcessTimes");
9102
9103 DEFSYM (QCloaded_from, ":loaded-from");
9104
9105 g_b_init_is_windows_9x = 0;
9106 g_b_init_open_process_token = 0;
9107 g_b_init_get_token_information = 0;
9108 g_b_init_lookup_account_sid = 0;
9109 g_b_init_get_sid_sub_authority = 0;
9110 g_b_init_get_sid_sub_authority_count = 0;
9111 g_b_init_get_security_info = 0;
9112 g_b_init_get_file_security_w = 0;
9113 g_b_init_get_file_security_a = 0;
9114 g_b_init_get_security_descriptor_owner = 0;
9115 g_b_init_get_security_descriptor_group = 0;
9116 g_b_init_is_valid_sid = 0;
9117 g_b_init_create_toolhelp32_snapshot = 0;
9118 g_b_init_process32_first = 0;
9119 g_b_init_process32_next = 0;
9120 g_b_init_open_thread_token = 0;
9121 g_b_init_impersonate_self = 0;
9122 g_b_init_revert_to_self = 0;
9123 g_b_init_get_process_memory_info = 0;
9124 g_b_init_get_process_working_set_size = 0;
9125 g_b_init_global_memory_status = 0;
9126 g_b_init_global_memory_status_ex = 0;
9127 g_b_init_equal_sid = 0;
9128 g_b_init_copy_sid = 0;
9129 g_b_init_get_length_sid = 0;
9130 g_b_init_get_native_system_info = 0;
9131 g_b_init_get_system_times = 0;
9132 g_b_init_create_symbolic_link_w = 0;
9133 g_b_init_create_symbolic_link_a = 0;
9134 g_b_init_get_security_descriptor_dacl = 0;
9135 g_b_init_convert_sd_to_sddl = 0;
9136 g_b_init_convert_sddl_to_sd = 0;
9137 g_b_init_is_valid_security_descriptor = 0;
9138 g_b_init_set_file_security_w = 0;
9139 g_b_init_set_file_security_a = 0;
9140 g_b_init_set_named_security_info_w = 0;
9141 g_b_init_set_named_security_info_a = 0;
9142 g_b_init_get_adapters_info = 0;
9143 g_b_init_compare_string_w = 0;
9144 num_of_processors = 0;
9145 /* The following sets a handler for shutdown notifications for
9146 console apps. This actually applies to Emacs in both console and
9147 GUI modes, since we had to fool windows into thinking emacs is a
9148 console application to get console mode to work. */
9149 SetConsoleCtrlHandler (shutdown_handler, TRUE);
9150
9151 /* "None" is the default group name on standalone workstations. */
9152 strcpy (dflt_group_name, "None");
9153
9154 /* Reset, in case it has some value inherited from dump time. */
9155 w32_stat_get_owner_group = 0;
9156
9157 /* If w32_unicode_filenames is non-zero, we will be using Unicode
9158 (a.k.a. "wide") APIs to invoke functions that accept file
9159 names. */
9160 if (is_windows_9x ())
9161 w32_unicode_filenames = 0;
9162 else
9163 w32_unicode_filenames = 1;
9164 }
9165
9166 /* For make-serial-process */
9167 int
9168 serial_open (Lisp_Object port_obj)
9169 {
9170 char *port = SSDATA (port_obj);
9171 HANDLE hnd;
9172 child_process *cp;
9173 int fd = -1;
9174
9175 hnd = CreateFile (port, GENERIC_READ | GENERIC_WRITE, 0, 0,
9176 OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
9177 if (hnd == INVALID_HANDLE_VALUE)
9178 error ("Could not open %s", port);
9179 fd = (int) _open_osfhandle ((intptr_t) hnd, 0);
9180 if (fd == -1)
9181 error ("Could not open %s", port);
9182
9183 cp = new_child ();
9184 if (!cp)
9185 error ("Could not create child process");
9186 cp->fd = fd;
9187 cp->status = STATUS_READ_ACKNOWLEDGED;
9188 fd_info[ fd ].hnd = hnd;
9189 fd_info[ fd ].flags |=
9190 FILE_READ | FILE_WRITE | FILE_BINARY | FILE_SERIAL;
9191 if (fd_info[ fd ].cp != NULL)
9192 {
9193 error ("fd_info[fd = %d] is already in use", fd);
9194 }
9195 fd_info[ fd ].cp = cp;
9196 cp->ovl_read.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
9197 if (cp->ovl_read.hEvent == NULL)
9198 error ("Could not create read event");
9199 cp->ovl_write.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
9200 if (cp->ovl_write.hEvent == NULL)
9201 error ("Could not create write event");
9202
9203 return fd;
9204 }
9205
9206 /* For serial-process-configure */
9207 void
9208 serial_configure (struct Lisp_Process *p, Lisp_Object contact)
9209 {
9210 Lisp_Object childp2 = Qnil;
9211 Lisp_Object tem = Qnil;
9212 HANDLE hnd;
9213 DCB dcb;
9214 COMMTIMEOUTS ct;
9215 char summary[4] = "???"; /* This usually becomes "8N1". */
9216
9217 if ((fd_info[ p->outfd ].flags & FILE_SERIAL) == 0)
9218 error ("Not a serial process");
9219 hnd = fd_info[ p->outfd ].hnd;
9220
9221 childp2 = Fcopy_sequence (p->childp);
9222
9223 /* Initialize timeouts for blocking read and blocking write. */
9224 if (!GetCommTimeouts (hnd, &ct))
9225 error ("GetCommTimeouts() failed");
9226 ct.ReadIntervalTimeout = 0;
9227 ct.ReadTotalTimeoutMultiplier = 0;
9228 ct.ReadTotalTimeoutConstant = 0;
9229 ct.WriteTotalTimeoutMultiplier = 0;
9230 ct.WriteTotalTimeoutConstant = 0;
9231 if (!SetCommTimeouts (hnd, &ct))
9232 error ("SetCommTimeouts() failed");
9233 /* Read port attributes and prepare default configuration. */
9234 memset (&dcb, 0, sizeof (dcb));
9235 dcb.DCBlength = sizeof (DCB);
9236 if (!GetCommState (hnd, &dcb))
9237 error ("GetCommState() failed");
9238 dcb.fBinary = TRUE;
9239 dcb.fNull = FALSE;
9240 dcb.fAbortOnError = FALSE;
9241 /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
9242 dcb.ErrorChar = 0;
9243 dcb.EofChar = 0;
9244 dcb.EvtChar = 0;
9245
9246 /* Configure speed. */
9247 if (!NILP (Fplist_member (contact, QCspeed)))
9248 tem = Fplist_get (contact, QCspeed);
9249 else
9250 tem = Fplist_get (p->childp, QCspeed);
9251 CHECK_NUMBER (tem);
9252 dcb.BaudRate = XINT (tem);
9253 childp2 = Fplist_put (childp2, QCspeed, tem);
9254
9255 /* Configure bytesize. */
9256 if (!NILP (Fplist_member (contact, QCbytesize)))
9257 tem = Fplist_get (contact, QCbytesize);
9258 else
9259 tem = Fplist_get (p->childp, QCbytesize);
9260 if (NILP (tem))
9261 tem = make_number (8);
9262 CHECK_NUMBER (tem);
9263 if (XINT (tem) != 7 && XINT (tem) != 8)
9264 error (":bytesize must be nil (8), 7, or 8");
9265 dcb.ByteSize = XINT (tem);
9266 summary[0] = XINT (tem) + '0';
9267 childp2 = Fplist_put (childp2, QCbytesize, tem);
9268
9269 /* Configure parity. */
9270 if (!NILP (Fplist_member (contact, QCparity)))
9271 tem = Fplist_get (contact, QCparity);
9272 else
9273 tem = Fplist_get (p->childp, QCparity);
9274 if (!NILP (tem) && !EQ (tem, Qeven) && !EQ (tem, Qodd))
9275 error (":parity must be nil (no parity), `even', or `odd'");
9276 dcb.fParity = FALSE;
9277 dcb.Parity = NOPARITY;
9278 dcb.fErrorChar = FALSE;
9279 if (NILP (tem))
9280 {
9281 summary[1] = 'N';
9282 }
9283 else if (EQ (tem, Qeven))
9284 {
9285 summary[1] = 'E';
9286 dcb.fParity = TRUE;
9287 dcb.Parity = EVENPARITY;
9288 dcb.fErrorChar = TRUE;
9289 }
9290 else if (EQ (tem, Qodd))
9291 {
9292 summary[1] = 'O';
9293 dcb.fParity = TRUE;
9294 dcb.Parity = ODDPARITY;
9295 dcb.fErrorChar = TRUE;
9296 }
9297 childp2 = Fplist_put (childp2, QCparity, tem);
9298
9299 /* Configure stopbits. */
9300 if (!NILP (Fplist_member (contact, QCstopbits)))
9301 tem = Fplist_get (contact, QCstopbits);
9302 else
9303 tem = Fplist_get (p->childp, QCstopbits);
9304 if (NILP (tem))
9305 tem = make_number (1);
9306 CHECK_NUMBER (tem);
9307 if (XINT (tem) != 1 && XINT (tem) != 2)
9308 error (":stopbits must be nil (1 stopbit), 1, or 2");
9309 summary[2] = XINT (tem) + '0';
9310 if (XINT (tem) == 1)
9311 dcb.StopBits = ONESTOPBIT;
9312 else if (XINT (tem) == 2)
9313 dcb.StopBits = TWOSTOPBITS;
9314 childp2 = Fplist_put (childp2, QCstopbits, tem);
9315
9316 /* Configure flowcontrol. */
9317 if (!NILP (Fplist_member (contact, QCflowcontrol)))
9318 tem = Fplist_get (contact, QCflowcontrol);
9319 else
9320 tem = Fplist_get (p->childp, QCflowcontrol);
9321 if (!NILP (tem) && !EQ (tem, Qhw) && !EQ (tem, Qsw))
9322 error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
9323 dcb.fOutxCtsFlow = FALSE;
9324 dcb.fOutxDsrFlow = FALSE;
9325 dcb.fDtrControl = DTR_CONTROL_DISABLE;
9326 dcb.fDsrSensitivity = FALSE;
9327 dcb.fTXContinueOnXoff = FALSE;
9328 dcb.fOutX = FALSE;
9329 dcb.fInX = FALSE;
9330 dcb.fRtsControl = RTS_CONTROL_DISABLE;
9331 dcb.XonChar = 17; /* Control-Q */
9332 dcb.XoffChar = 19; /* Control-S */
9333 if (NILP (tem))
9334 {
9335 /* Already configured. */
9336 }
9337 else if (EQ (tem, Qhw))
9338 {
9339 dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
9340 dcb.fOutxCtsFlow = TRUE;
9341 }
9342 else if (EQ (tem, Qsw))
9343 {
9344 dcb.fOutX = TRUE;
9345 dcb.fInX = TRUE;
9346 }
9347 childp2 = Fplist_put (childp2, QCflowcontrol, tem);
9348
9349 /* Activate configuration. */
9350 if (!SetCommState (hnd, &dcb))
9351 error ("SetCommState() failed");
9352
9353 childp2 = Fplist_put (childp2, QCsummary, build_string (summary));
9354 pset_childp (p, childp2);
9355 }
9356
9357 #ifdef HAVE_GNUTLS
9358
9359 ssize_t
9360 emacs_gnutls_pull (gnutls_transport_ptr_t p, void* buf, size_t sz)
9361 {
9362 int n, err;
9363 struct Lisp_Process *process = (struct Lisp_Process *)p;
9364 int fd = process->infd;
9365
9366 n = sys_read (fd, (char*)buf, sz);
9367
9368 if (n >= 0)
9369 return n;
9370
9371 err = errno;
9372
9373 /* Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
9374 if (err == EWOULDBLOCK)
9375 err = EAGAIN;
9376
9377 emacs_gnutls_transport_set_errno (process->gnutls_state, err);
9378
9379 return -1;
9380 }
9381
9382 ssize_t
9383 emacs_gnutls_push (gnutls_transport_ptr_t p, const void* buf, size_t sz)
9384 {
9385 struct Lisp_Process *process = (struct Lisp_Process *)p;
9386 int fd = process->outfd;
9387 ssize_t n = sys_write (fd, buf, sz);
9388
9389 /* 0 or more bytes written means everything went fine. */
9390 if (n >= 0)
9391 return n;
9392
9393 /* Negative bytes written means we got an error in errno.
9394 Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
9395 emacs_gnutls_transport_set_errno (process->gnutls_state,
9396 errno == EWOULDBLOCK ? EAGAIN : errno);
9397
9398 return -1;
9399 }
9400 #endif /* HAVE_GNUTLS */
9401
9402 /* end of w32.c */