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