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