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