* lisp/icomplete.el: Change separator; add ido-style commands.
[emacs.git] / src / w32.c
blobc8e16dfaa94462f0f0ba0c6566930137e90fc242
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.
4 This file is part of GNU Emacs.
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.
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.
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/>. */
20 Geoff Voelker (voelker@cs.washington.edu) 7-29-94
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>
37 /* must include CRT headers *before* config.h */
39 #include <config.h>
40 #include <mbstring.h> /* for _mbspbrk */
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
56 #undef close
57 #undef dup
58 #undef dup2
59 #undef pipe
60 #undef read
61 #undef write
63 #undef strerror
65 #undef localtime
67 #include "lisp.h"
69 #include <pwd.h>
70 #include <grp.h>
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;
91 #include <lmcons.h>
92 #include <shlobj.h>
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
118 #include <winioctl.h>
119 #include <aclapi.h>
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. */
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;
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
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
181 #include "w32.h"
182 #include <dirent.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 */
190 #include "careadlinkat.h"
191 #include "allocator.h"
193 /* For serial_configure and serial_open. */
194 #include "process.h"
196 typedef HRESULT (WINAPI * ShGetFolderPath_fn)
197 (IN HWND, IN int, IN HANDLE, IN DWORD, OUT char *);
199 Lisp_Object QCloaded_from;
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);
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 *);
216 /* Initialization states.
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;
254 BEGIN: Wrapper functions around OpenProcessToken
255 and other functions in advapi32.dll that are only
256 supported in Windows NT / 2k / XP
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);
276 GetProcessTimes_Proc get_process_times_fn = NULL;
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);
372 /* ** A utility function ** */
373 static BOOL
374 is_windows_9x (void)
376 static BOOL s_b_ret = 0;
377 OSVERSIONINFO os_ver;
378 if (g_b_init_is_windows_9x == 0)
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))
385 s_b_ret = (os_ver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
388 return s_b_ret;
391 static Lisp_Object ltime (ULONGLONG);
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)
399 if (get_process_times_fn)
401 FILETIME create, exit, kernel, user;
402 HANDLE proc = GetCurrentProcess ();
403 if ((*get_process_times_fn) (proc, &create, &exit, &kernel, &user))
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);
415 return Fcurrent_time ();
418 /* ** The wrapper functions ** */
420 static BOOL WINAPI
421 open_process_token (HANDLE ProcessHandle,
422 DWORD DesiredAccess,
423 PHANDLE TokenHandle)
425 static OpenProcessToken_Proc s_pfn_Open_Process_Token = NULL;
426 HMODULE hm_advapi32 = NULL;
427 if (is_windows_9x () == TRUE)
429 return FALSE;
431 if (g_b_init_open_process_token == 0)
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");
438 if (s_pfn_Open_Process_Token == NULL)
440 return FALSE;
442 return (
443 s_pfn_Open_Process_Token (
444 ProcessHandle,
445 DesiredAccess,
446 TokenHandle)
450 static BOOL WINAPI
451 get_token_information (HANDLE TokenHandle,
452 TOKEN_INFORMATION_CLASS TokenInformationClass,
453 LPVOID TokenInformation,
454 DWORD TokenInformationLength,
455 PDWORD ReturnLength)
457 static GetTokenInformation_Proc s_pfn_Get_Token_Information = NULL;
458 HMODULE hm_advapi32 = NULL;
459 if (is_windows_9x () == TRUE)
461 return FALSE;
463 if (g_b_init_get_token_information == 0)
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");
470 if (s_pfn_Get_Token_Information == NULL)
472 return FALSE;
474 return (
475 s_pfn_Get_Token_Information (
476 TokenHandle,
477 TokenInformationClass,
478 TokenInformation,
479 TokenInformationLength,
480 ReturnLength)
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)
493 static LookupAccountSid_Proc s_pfn_Lookup_Account_Sid = NULL;
494 HMODULE hm_advapi32 = NULL;
495 if (is_windows_9x () == TRUE)
497 return FALSE;
499 if (g_b_init_lookup_account_sid == 0)
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);
506 if (s_pfn_Lookup_Account_Sid == NULL)
508 return FALSE;
510 return (
511 s_pfn_Lookup_Account_Sid (
512 lpSystemName,
513 Sid,
514 Name,
515 cbName,
516 DomainName,
517 cbDomainName,
518 peUse)
522 static PDWORD WINAPI
523 get_sid_sub_authority (PSID pSid, DWORD n)
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)
530 return &zero;
532 if (g_b_init_get_sid_sub_authority == 0)
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");
540 if (s_pfn_Get_Sid_Sub_Authority == NULL)
542 return &zero;
544 return (s_pfn_Get_Sid_Sub_Authority (pSid, n));
547 static PUCHAR WINAPI
548 get_sid_sub_authority_count (PSID pSid)
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)
555 return &zero;
557 if (g_b_init_get_sid_sub_authority_count == 0)
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");
565 if (s_pfn_Get_Sid_Sub_Authority_Count == NULL)
567 return &zero;
569 return (s_pfn_Get_Sid_Sub_Authority_Count (pSid));
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)
582 static GetSecurityInfo_Proc s_pfn_Get_Security_Info = NULL;
583 HMODULE hm_advapi32 = NULL;
584 if (is_windows_9x () == TRUE)
586 return FALSE;
588 if (g_b_init_get_security_info == 0)
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");
596 if (s_pfn_Get_Security_Info == NULL)
598 return FALSE;
600 return (s_pfn_Get_Security_Info (handle, ObjectType, SecurityInfo,
601 ppsidOwner, ppsidGroup, ppDacl, ppSacl,
602 ppSecurityDescriptor));
605 static BOOL WINAPI
606 get_file_security (LPCTSTR lpFileName,
607 SECURITY_INFORMATION RequestedInformation,
608 PSECURITY_DESCRIPTOR pSecurityDescriptor,
609 DWORD nLength,
610 LPDWORD lpnLengthNeeded)
612 static GetFileSecurity_Proc s_pfn_Get_File_Security = NULL;
613 HMODULE hm_advapi32 = NULL;
614 if (is_windows_9x () == TRUE)
616 return FALSE;
618 if (g_b_init_get_file_security == 0)
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);
626 if (s_pfn_Get_File_Security == NULL)
628 return FALSE;
630 return (s_pfn_Get_File_Security (lpFileName, RequestedInformation,
631 pSecurityDescriptor, nLength,
632 lpnLengthNeeded));
635 static BOOL WINAPI
636 get_security_descriptor_owner (PSECURITY_DESCRIPTOR pSecurityDescriptor,
637 PSID *pOwner,
638 LPBOOL lpbOwnerDefaulted)
640 static GetSecurityDescriptorOwner_Proc s_pfn_Get_Security_Descriptor_Owner = NULL;
641 HMODULE hm_advapi32 = NULL;
642 if (is_windows_9x () == TRUE)
644 return FALSE;
646 if (g_b_init_get_security_descriptor_owner == 0)
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");
654 if (s_pfn_Get_Security_Descriptor_Owner == NULL)
656 return FALSE;
658 return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor, pOwner,
659 lpbOwnerDefaulted));
662 static BOOL WINAPI
663 get_security_descriptor_group (PSECURITY_DESCRIPTOR pSecurityDescriptor,
664 PSID *pGroup,
665 LPBOOL lpbGroupDefaulted)
667 static GetSecurityDescriptorGroup_Proc s_pfn_Get_Security_Descriptor_Group = NULL;
668 HMODULE hm_advapi32 = NULL;
669 if (is_windows_9x () == TRUE)
671 return FALSE;
673 if (g_b_init_get_security_descriptor_group == 0)
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");
681 if (s_pfn_Get_Security_Descriptor_Group == NULL)
683 return FALSE;
685 return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor, pGroup,
686 lpbGroupDefaulted));
689 static BOOL WINAPI
690 is_valid_sid (PSID sid)
692 static IsValidSid_Proc s_pfn_Is_Valid_Sid = NULL;
693 HMODULE hm_advapi32 = NULL;
694 if (is_windows_9x () == TRUE)
696 return FALSE;
698 if (g_b_init_is_valid_sid == 0)
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");
706 if (s_pfn_Is_Valid_Sid == NULL)
708 return FALSE;
710 return (s_pfn_Is_Valid_Sid (sid));
713 static BOOL WINAPI
714 equal_sid (PSID sid1, PSID sid2)
716 static EqualSid_Proc s_pfn_Equal_Sid = NULL;
717 HMODULE hm_advapi32 = NULL;
718 if (is_windows_9x () == TRUE)
720 return FALSE;
722 if (g_b_init_equal_sid == 0)
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");
730 if (s_pfn_Equal_Sid == NULL)
732 return FALSE;
734 return (s_pfn_Equal_Sid (sid1, sid2));
737 static DWORD WINAPI
738 get_length_sid (PSID sid)
740 static GetLengthSid_Proc s_pfn_Get_Length_Sid = NULL;
741 HMODULE hm_advapi32 = NULL;
742 if (is_windows_9x () == TRUE)
744 return 0;
746 if (g_b_init_get_length_sid == 0)
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");
754 if (s_pfn_Get_Length_Sid == NULL)
756 return 0;
758 return (s_pfn_Get_Length_Sid (sid));
761 static BOOL WINAPI
762 copy_sid (DWORD destlen, PSID dest, PSID src)
764 static CopySid_Proc s_pfn_Copy_Sid = NULL;
765 HMODULE hm_advapi32 = NULL;
766 if (is_windows_9x () == TRUE)
768 return FALSE;
770 if (g_b_init_copy_sid == 0)
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");
778 if (s_pfn_Copy_Sid == NULL)
780 return FALSE;
782 return (s_pfn_Copy_Sid (destlen, dest, src));
786 END: Wrapper functions around OpenProcessToken
787 and other functions in advapi32.dll that are only
788 supported in Windows NT / 2k / XP
791 static void WINAPI
792 get_native_system_info (LPSYSTEM_INFO lpSystemInfo)
794 static GetNativeSystemInfo_Proc s_pfn_Get_Native_System_Info = NULL;
795 if (is_windows_9x () != TRUE)
797 if (g_b_init_get_native_system_info == 0)
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");
804 if (s_pfn_Get_Native_System_Info != NULL)
805 s_pfn_Get_Native_System_Info (lpSystemInfo);
807 else
808 lpSystemInfo->dwNumberOfProcessors = -1;
811 static BOOL WINAPI
812 get_system_times (LPFILETIME lpIdleTime,
813 LPFILETIME lpKernelTime,
814 LPFILETIME lpUserTime)
816 static GetSystemTimes_Proc s_pfn_Get_System_times = NULL;
817 if (is_windows_9x () == TRUE)
819 return FALSE;
821 if (g_b_init_get_system_times == 0)
823 g_b_init_get_system_times = 1;
824 s_pfn_Get_System_times =
825 (GetSystemTimes_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
826 "GetSystemTimes");
828 if (s_pfn_Get_System_times == NULL)
829 return FALSE;
830 return (s_pfn_Get_System_times (lpIdleTime, lpKernelTime, lpUserTime));
833 static BOOLEAN WINAPI
834 create_symbolic_link (LPTSTR lpSymlinkFilename,
835 LPTSTR lpTargetFileName,
836 DWORD dwFlags)
838 static CreateSymbolicLink_Proc s_pfn_Create_Symbolic_Link = NULL;
839 BOOLEAN retval;
841 if (is_windows_9x () == TRUE)
843 errno = ENOSYS;
844 return 0;
846 if (g_b_init_create_symbolic_link == 0)
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
859 if (s_pfn_Create_Symbolic_Link == NULL)
861 errno = ENOSYS;
862 return 0;
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)
871 TOKEN_PRIVILEGES priv_current;
873 if (enable_privilege (SE_CREATE_SYMBOLIC_LINK_NAME, TRUE, &priv_current))
875 retval = s_pfn_Create_Symbolic_Link (lpSymlinkFilename, lpTargetFileName,
876 dwFlags);
877 restore_privilege (&priv_current);
878 revert_to_self ();
881 return retval;
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.
888 This is called from alloc.c:valid_pointer_p. */
890 w32_valid_pointer_p (void *p, int size)
892 SIZE_T done;
893 HANDLE h = OpenProcess (PROCESS_VM_READ, FALSE, GetCurrentProcessId ());
895 if (h)
897 unsigned char *buf = alloca (size);
898 int retval = ReadProcessMemory (h, p, buf, size, &done);
900 CloseHandle (h);
901 return retval;
903 else
904 return -1;
907 static char startup_dir[MAXPATHLEN];
909 /* Get the current working directory. */
910 char *
911 getcwd (char *dir, int dirsize)
913 if (!dirsize)
915 errno = EINVAL;
916 return NULL;
918 if (dirsize <= strlen (startup_dir))
920 errno = ERANGE;
921 return NULL;
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
935 /* Emulate getloadavg. */
937 struct load_sample {
938 time_t sample_time;
939 ULONGLONG idle;
940 ULONGLONG kernel;
941 ULONGLONG user;
944 /* Number of processors on this machine. */
945 static unsigned num_of_processors;
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]);
952 static int
953 buf_next (int from)
955 int next_idx = from + 1;
957 if (next_idx >= max_idx)
958 next_idx = 0;
960 return next_idx;
963 static int
964 buf_prev (int from)
966 int prev_idx = from - 1;
968 if (prev_idx < 0)
969 prev_idx = max_idx - 1;
971 return prev_idx;
974 static void
975 sample_system_load (ULONGLONG *idle, ULONGLONG *kernel, ULONGLONG *user)
977 SYSTEM_INFO sysinfo;
978 FILETIME ft_idle, ft_user, ft_kernel;
980 /* Initialize the number of processors on this machine. */
981 if (num_of_processors <= 0)
983 get_native_system_info (&sysinfo);
984 num_of_processors = sysinfo.dwNumberOfProcessors;
985 if (num_of_processors <= 0)
987 GetSystemInfo (&sysinfo);
988 num_of_processors = sysinfo.dwNumberOfProcessors;
990 if (num_of_processors <= 0)
991 num_of_processors = 1;
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. */
999 if (get_system_times (&ft_idle, &ft_kernel, &ft_user))
1001 ULARGE_INTEGER uidle, ukernel, uuser;
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;
1010 else
1012 *idle = 0;
1013 *kernel = 0;
1014 *user = 0;
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)
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;
1030 if (first_idx != last_idx)
1032 for (idx = buf_prev (last_idx); ; idx = buf_prev (idx))
1034 tdiff = difftime (now, samples[idx].sample_time);
1035 if (tdiff >= span - 2*DBL_EPSILON*now)
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;
1042 retval = (1.0 - idl / sys) * num_of_processors;
1043 break;
1045 if (idx == first_idx)
1046 break;
1050 return retval;
1054 getloadavg (double loadavg[], int nelem)
1056 int elem;
1057 ULONGLONG idle, kernel, user;
1058 time_t now = time (NULL);
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)
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);
1080 for (elem = 0; elem < nelem; elem++)
1082 double avg = getavg (elem);
1084 if (avg < 0)
1085 break;
1086 loadavg[elem] = avg;
1089 return elem;
1092 /* Emulate getpwuid, getpwnam and others. */
1094 #define PASSWD_FIELD_SIZE 256
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];
1102 static struct passwd dflt_passwd =
1104 dflt_passwd_name,
1105 dflt_passwd_passwd,
1109 dflt_passwd_gecos,
1110 dflt_passwd_dir,
1111 dflt_passwd_shell,
1114 static char dflt_group_name[GNLEN+1];
1116 static struct group dflt_group =
1118 /* When group information is not available, we return this as the
1119 group for all files. */
1120 dflt_group_name,
1124 unsigned
1125 getuid (void)
1127 return dflt_passwd.pw_uid;
1130 unsigned
1131 geteuid (void)
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 ();
1139 unsigned
1140 getgid (void)
1142 return dflt_passwd.pw_gid;
1145 unsigned
1146 getegid (void)
1148 return getgid ();
1151 struct passwd *
1152 getpwuid (unsigned uid)
1154 if (uid == dflt_passwd.pw_uid)
1155 return &dflt_passwd;
1156 return NULL;
1159 struct group *
1160 getgrgid (gid_t gid)
1162 return &dflt_group;
1165 struct passwd *
1166 getpwnam (char *name)
1168 struct passwd *pw;
1170 pw = getpwuid (getuid ());
1171 if (!pw)
1172 return pw;
1174 if (xstrcasecmp (name, pw->pw_name))
1175 return NULL;
1177 return pw;
1180 static void
1181 init_user_info (void)
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.
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). */
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;
1201 result = open_process_token (GetCurrentProcess (), TOKEN_QUERY, &token);
1202 if (result)
1204 result = get_token_information (token, TokenUser, NULL, 0, &blen);
1205 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
1207 buf = xmalloc (blen);
1208 result = get_token_information (token, TokenUser,
1209 (LPVOID)buf, blen, &needed);
1210 if (result)
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);
1218 else
1219 result = FALSE;
1221 if (result)
1223 strcpy (dflt_passwd.pw_name, uname);
1224 /* Determine a reasonable uid value. */
1225 if (xstrcasecmp ("administrator", uname) == 0)
1227 dflt_passwd.pw_uid = 500; /* well-known Administrator uid */
1228 dflt_passwd.pw_gid = 513; /* well-known None gid */
1230 else
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);
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)
1241 buf = xrealloc (buf, blen = needed);
1242 result = get_token_information (token, TokenPrimaryGroup,
1243 (LPVOID)buf, blen, &needed);
1245 if (result)
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);
1258 else
1259 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
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))
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;
1273 else
1275 strcpy (dflt_passwd.pw_name, "unknown");
1276 dflt_passwd.pw_uid = 123;
1277 dflt_passwd.pw_gid = 123;
1279 dflt_group.gr_gid = dflt_passwd.pw_gid;
1281 /* Ensure HOME and SHELL are defined. */
1282 if (getenv ("HOME") == NULL)
1283 emacs_abort ();
1284 if (getenv ("SHELL") == NULL)
1285 emacs_abort ();
1287 /* Set dir and shell from environment variables. */
1288 strcpy (dflt_passwd.pw_dir, getenv ("HOME"));
1289 strcpy (dflt_passwd.pw_shell, getenv ("SHELL"));
1291 xfree (buf);
1292 if (token)
1293 CloseHandle (token);
1297 random (void)
1299 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
1300 return ((rand () << 15) | rand ());
1303 void
1304 srandom (int seed)
1306 srand (seed);
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. */
1314 static void
1315 normalize_filename (register char *fp, char path_sep)
1317 char sep;
1318 char *elem;
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')
1327 *fp += 'a' - 'A';
1328 fp += 2;
1331 if (NILP (Vw32_downcase_file_names))
1333 while (*fp)
1335 if (*fp == '/' || *fp == '\\')
1336 *fp = path_sep;
1337 fp++;
1339 return;
1342 sep = path_sep; /* convert to this path separator */
1343 elem = fp; /* start of current path element */
1345 do {
1346 if (*fp >= 'a' && *fp <= 'z')
1347 elem = 0; /* don't convert this element */
1349 if (*fp == 0 || *fp == ':')
1351 sep = *fp; /* restore current separator (or 0) */
1352 *fp = '/'; /* after conversion of this element */
1355 if (*fp == '/' || *fp == '\\')
1357 if (elem && elem != fp)
1359 *fp = 0; /* temporary end of string */
1360 _strlwr (elem); /* while we convert to lower case */
1362 *fp = sep; /* convert (or restore) path separator */
1363 elem = fp + 1; /* next element starts after separator */
1364 sep = path_sep;
1366 } while (*fp++);
1369 /* Destructively turn backslashes into slashes. */
1370 void
1371 dostounix_filename (register char *p)
1373 normalize_filename (p, '/');
1376 /* Destructively turn slashes into backslashes. */
1377 void
1378 unixtodos_filename (register char *p)
1380 normalize_filename (p, '\\');
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)
1389 unsigned char *np = buf;
1390 unsigned char *startp = buf;
1391 unsigned char *endp = buf + n;
1393 if (n == 0)
1394 return n;
1395 while (buf < endp - 1)
1397 if (*buf == 0x0d)
1399 if (*(++buf) != 0x0a)
1400 *np++ = 0x0d;
1402 else
1403 *np++ = *buf++;
1405 if (buf < endp)
1406 *np++ = *buf++;
1407 return np - startp;
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)
1415 char * start = name;
1417 if (name == NULL)
1418 return 0;
1420 /* find the root name of the volume if given */
1421 if (isalpha (name[0]) && name[1] == ':')
1423 /* skip past drive specifier */
1424 name += 2;
1425 if (IS_DIRECTORY_SEP (name[0]))
1426 name++;
1428 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
1430 int slashes = 2;
1431 name += 2;
1434 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
1435 break;
1436 name++;
1438 while ( *name );
1439 if (IS_DIRECTORY_SEP (name[0]))
1440 name++;
1443 if (pPath)
1444 *pPath = name;
1446 return name - start;
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)
1453 WIN32_FIND_DATA find_data;
1454 HANDLE dir_handle;
1455 int len = 0;
1457 /* must be valid filename, no wild cards or other invalid characters */
1458 if (_mbspbrk (name, "*?|<>\""))
1459 return 0;
1461 dir_handle = FindFirstFile (name, &find_data);
1462 if (dir_handle != INVALID_HANDLE_VALUE)
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);
1470 return len;
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)
1477 char * o = buf;
1478 char * p;
1479 char * q;
1480 char full[ MAX_PATH ];
1481 int len;
1483 len = strlen (name);
1484 if (len >= MAX_PATH)
1485 return FALSE;
1487 /* Use local copy for destructive modification. */
1488 memcpy (full, name, len+1);
1489 unixtodos_filename (full);
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;
1498 while (p != NULL && *p)
1500 q = p;
1501 p = strchr (q, '\\');
1502 if (p) *p = '\0';
1503 len = get_long_basename (full, o, size);
1504 if (len > 0)
1506 o += len;
1507 size -= len;
1508 if (p != NULL)
1510 *p++ = '\\';
1511 if (size < 2)
1512 return FALSE;
1513 *o++ = '\\';
1514 size--;
1515 *o = '\0';
1518 else
1519 return FALSE;
1522 return TRUE;
1525 static int
1526 is_unc_volume (const char *filename)
1528 const char *ptr = filename;
1530 if (!IS_DIRECTORY_SEP (ptr[0]) || !IS_DIRECTORY_SEP (ptr[1]) || !ptr[2])
1531 return 0;
1533 if (_mbspbrk (ptr + 2, "*?|<>\"\\/"))
1534 return 0;
1536 return 1;
1539 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
1541 LPBYTE
1542 w32_get_resource (char *key, LPDWORD lpdwtype)
1544 LPBYTE lpvalue;
1545 HKEY hrootkey = NULL;
1546 DWORD cbData;
1548 /* Check both the current user and the local machine to see if
1549 we have any resources. */
1551 if (RegOpenKeyEx (HKEY_CURRENT_USER, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
1553 lpvalue = NULL;
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)
1559 RegCloseKey (hrootkey);
1560 return (lpvalue);
1563 xfree (lpvalue);
1565 RegCloseKey (hrootkey);
1568 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
1570 lpvalue = NULL;
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)
1576 RegCloseKey (hrootkey);
1577 return (lpvalue);
1580 xfree (lpvalue);
1582 RegCloseKey (hrootkey);
1585 return (NULL);
1588 char *get_emacs_configuration (void);
1590 void
1591 init_environment (char ** argv)
1593 static const char * const tempdirs[] = {
1594 "$TMPDIR", "$TEMP", "$TMP", "c:/"
1597 int i;
1599 const int imax = sizeof (tempdirs) / sizeof (tempdirs[0]);
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++)
1607 const char *tmp = tempdirs[i];
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. */
1616 /* MSVCRT's _access crashes with D_OK. */
1617 if (tmp && faccessat (AT_FDCWD, tmp, D_OK, AT_EACCESS) == 0)
1619 char * var = alloca (strlen (tmp) + 8);
1620 sprintf (var, "TMPDIR=%s", tmp);
1621 _putenv (strdup (var));
1622 break;
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: ");
1632 /* Check for environment variables and use registry settings if they
1633 don't exist. Fallback on default values where applicable. */
1635 int i;
1636 LPBYTE lpval;
1637 DWORD dwType;
1638 char locale_name[32];
1639 char default_home[MAX_PATH];
1640 int appdata = 0;
1642 static const struct env_entry
1644 char * name;
1645 char * def_value;
1646 } dflt_envvars[] =
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},
1665 #define N_ENV_VARS sizeof (dflt_envvars)/sizeof (dflt_envvars[0])
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];
1673 for (i = 0; i < N_ENV_VARS; i++)
1674 env_vars[i] = dflt_envvars[i];
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"))
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");
1689 if (get_folder_path != NULL)
1691 profile_result = get_folder_path (NULL, CSIDL_APPDATA, NULL,
1692 0, default_home);
1694 /* If we can't get the appdata dir, revert to old behavior. */
1695 if (profile_result == S_OK)
1697 env_vars[0].def_value = default_home;
1698 appdata = 1;
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)))
1708 for (i = 0; i < N_ENV_VARS; i++)
1710 if (strcmp (env_vars[i].name, "LANG") == 0)
1712 env_vars[i].def_value = locale_name;
1713 break;
1718 #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
1720 /* Treat emacs_dir specially: set it unconditionally based on our
1721 location. */
1723 char *p;
1724 char modname[MAX_PATH];
1726 if (!GetModuleFileName (NULL, modname, MAX_PATH))
1727 emacs_abort ();
1728 if ((p = strrchr (modname, '\\')) == NULL)
1729 emacs_abort ();
1730 *p = 0;
1732 if ((p = strrchr (modname, '\\')) && xstrcasecmp (p, "\\bin") == 0)
1734 char buf[SET_ENV_BUF_SIZE];
1736 *p = 0;
1737 for (p = modname; *p; p++)
1738 if (*p == '\\') *p = '/';
1740 _snprintf (buf, sizeof (buf)-1, "emacs_dir=%s", modname);
1741 _putenv (strdup (buf));
1743 /* Handle running emacs from the build directory: src/oo-spd/i386/ */
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))
1751 *p = 0;
1752 p = strrchr (modname, '\\');
1753 if (p != NULL)
1755 *p = 0;
1756 p = strrchr (modname, '\\');
1757 if (p && xstrcasecmp (p, "\\src") == 0)
1759 char buf[SET_ENV_BUF_SIZE];
1761 *p = 0;
1762 for (p = modname; *p; p++)
1763 if (*p == '\\') *p = '/';
1765 _snprintf (buf, sizeof (buf)-1, "emacs_dir=%s", modname);
1766 _putenv (strdup (buf));
1772 for (i = 0; i < N_ENV_VARS; i++)
1774 if (!getenv (env_vars[i].name))
1776 int dont_free = 0;
1778 if ((lpval = w32_get_resource (env_vars[i].name, &dwType)) == NULL
1779 /* Also ignore empty environment variables. */
1780 || *lpval == 0)
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);
1794 if (lpval)
1796 char buf1[SET_ENV_BUF_SIZE], buf2[SET_ENV_BUF_SIZE];
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)
1804 _snprintf (buf2, sizeof (buf2)-1, "%s=%s", env_vars[i].name,
1805 buf1);
1806 _putenv (strdup (buf2));
1809 if (!dont_free)
1810 xfree (lpval);
1816 /* Rebuild system configuration to reflect invoking system. */
1817 Vsystem_configuration = build_string (EMACS_CONFIGURATION);
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.
1827 The same applies to COMSPEC. */
1829 char ** envp;
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);
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 ();
1845 static char modname[MAX_PATH];
1847 if (!GetModuleFileName (NULL, modname, MAX_PATH))
1848 emacs_abort ();
1849 argv[0] = modname;
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);
1857 init_user_info ();
1860 /* Called from expand-file-name when default-directory is not a string. */
1862 char *
1863 emacs_root_dir (void)
1865 static char root_dir[FILENAME_MAX];
1866 const char *p;
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;
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. */
1882 char *
1883 get_emacs_configuration (void)
1885 char *arch, *oem, *os;
1886 int build_num;
1887 static char configuration_buffer[32];
1889 /* Determine the processor type. */
1890 switch (get_processor_type ())
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
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
1918 #ifdef PROCESSOR_ALPHA_21064
1919 case PROCESSOR_ALPHA_21064:
1920 arch = "alpha";
1921 break;
1922 #endif
1924 default:
1925 arch = "unknown";
1926 break;
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;
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";
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;
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);
1972 return configuration_buffer;
1975 char *
1976 get_emacs_configuration_options (void)
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
1998 size_t size = 0;
1999 int i;
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
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';
2016 for (i = 0; options[i]; i++)
2017 size += strlen (options[i]);
2019 options_buffer = xmalloc (size + 1);
2020 options_buffer[0] = '\0';
2022 for (i = 0; options[i]; i++)
2023 strcat (options_buffer, options[i]);
2025 return options_buffer;
2029 #include <sys/timeb.h>
2031 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
2032 void
2033 gettimeofday (struct timeval *tv, struct timezone *tz)
2035 struct _timeb tb;
2036 _ftime (&tb);
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)
2048 tz->tz_minuteswest = tb.timezone; /* minutes west of Greenwich */
2049 tz->tz_dsttime = tb.dstflag; /* type of dst correction */
2053 /* Emulate fdutimens. */
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. */
2065 fdutimens (int fd, char const *file, struct timespec const timespec[2])
2067 struct _utimbuf ut;
2069 if (!timespec)
2071 errno = ENOSYS;
2072 return -1;
2074 if (fd < 0 && !file)
2076 errno = EBADF;
2077 return -1;
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);
2088 /* ------------------------------------------------------------------------- */
2089 /* IO support and wrapper functions for the Windows API. */
2090 /* ------------------------------------------------------------------------- */
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)
2098 char *str = (char *) ctime (t);
2099 return (str ? str : "Sun Jan 01 00:00:00 1970");
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)
2108 Sleep (seconds * 1000);
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);
2115 /* parallel array of private info on file handles */
2116 filedesc fd_info [ MAXDESC ];
2118 typedef struct volume_info_data {
2119 struct volume_info_data * next;
2121 /* time when info was obtained */
2122 DWORD timestamp;
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;
2133 /* Global referenced by various functions. */
2134 static volume_info_data volume_info;
2136 /* Vector to indicate which drives are local and fixed (for which cached
2137 data never expires). */
2138 static BOOL fixed_drives[26];
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 )
2148 /* Cache support functions. */
2150 /* Simple linked list with linear search is sufficient. */
2151 static volume_info_data *volume_cache = NULL;
2153 static volume_info_data *
2154 lookup_volume_info (char * root_dir)
2156 volume_info_data * info;
2158 for (info = volume_cache; info; info = info->next)
2159 if (xstrcasecmp (info->root_dir, root_dir) == 0)
2160 break;
2161 return info;
2164 static void
2165 add_volume_info (char * root_dir, volume_info_data * info)
2167 info->root_dir = xstrdup (root_dir);
2168 info->next = volume_cache;
2169 volume_cache = info;
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)
2179 volume_info_data * info;
2180 char default_root[ MAX_PATH ];
2182 /* NULL for root_dir means use root from current directory. */
2183 if (root_dir == NULL)
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;
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.
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. */
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). */
2210 /* Map drive letter to UNC if remote. */
2211 if (isalpha (root_dir[0]) && !fixed[DRIVE_INDEX (root_dir[0])])
2213 char remote_name[ 256 ];
2214 char drive[3] = { root_dir[0], ':' };
2216 if (WNetGetConnection (drive, remote_name, sizeof (remote_name))
2217 == NO_ERROR)
2218 /* do something */ ;
2220 #endif
2222 info = lookup_volume_info (root_dir);
2224 if (info == NULL || ! VOLINFO_STILL_VALID (root_dir, info))
2226 char name[ 256 ];
2227 DWORD serialnum;
2228 DWORD maxcomp;
2229 DWORD flags;
2230 char type[ 256 ];
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;
2241 /* Cache the volume information for future use, overwriting existing
2242 entry if present. */
2243 if (info == NULL)
2245 info = xmalloc (sizeof (volume_info_data));
2246 add_volume_info (root_dir, info);
2248 else
2250 xfree (info->name);
2251 xfree (info->type);
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 ();
2262 return info;
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.
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)
2277 char temp[MAX_PATH];
2278 char *rootname = NULL; /* default to current volume */
2279 volume_info_data * info;
2281 if (name == NULL)
2282 return FALSE;
2284 /* Find the root name of the volume if given. */
2285 if (isalpha (name[0]) && name[1] == ':')
2287 rootname = temp;
2288 temp[0] = *name++;
2289 temp[1] = *name++;
2290 temp[2] = '\\';
2291 temp[3] = 0;
2293 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
2295 char *str = temp;
2296 int slashes = 4;
2297 rootname = temp;
2300 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
2301 break;
2302 *str++ = *name++;
2304 while ( *name );
2306 *str++ = '\\';
2307 *str = 0;
2310 if (pPath)
2311 *pPath = name;
2313 info = GetCachedVolumeInformation (rootname);
2314 if (info != NULL)
2316 /* Set global referenced by other functions. */
2317 volume_info = *info;
2318 return TRUE;
2320 return FALSE;
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)
2329 if (get_volume_info (name, pPath))
2330 return (volume_info.maxcomp == 12);
2331 return FALSE;
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)
2339 static char shortname[MAX_PATH];
2340 char * str = shortname;
2341 char c;
2342 char * path;
2343 const char * save_name = name;
2345 if (strlen (name) >= MAX_PATH)
2347 /* Return a filename which will cause callers to fail. */
2348 strcpy (shortname, "?");
2349 return shortname;
2352 if (is_fat_volume (name, (const char **)&path)) /* truncate to 8.3 */
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 */
2358 while (name < path)
2359 *str++ = *name++; /* skip past UNC header */
2361 while ((c = *name++))
2363 switch ( c )
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 )
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. */
2380 if (! *name ||
2381 *name == '.' ||
2382 IS_DIRECTORY_SEP (*name))
2384 *str++ = '.';
2385 dots--;
2387 else
2389 *str++ = '_';
2390 left--;
2391 dots = 0;
2394 else if ( !extn )
2396 *str++ = '.';
2397 extn = 1; /* we've got an extension */
2398 left = 3; /* 3 chars in extension */
2400 else
2402 /* any embedded dots after the first are converted to _ */
2403 *str++ = '_';
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 )
2414 *str++ = tolower (c); /* map to lower case (looks nicer) */
2415 left--;
2416 dots = 0; /* started a path component */
2418 break;
2421 *str = '\0';
2423 else
2425 strcpy (shortname, name);
2426 unixtodos_filename (shortname);
2429 if (pPath)
2430 *pPath = shortname + (path - save_name);
2432 return shortname;
2435 static int
2436 is_exec (const char * name)
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));
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. */
2451 struct dirent 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;
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);
2464 DIR *
2465 opendir (char *filename)
2467 DIR *dirp;
2469 /* Opening is done by FindFirstFile. However, a read is inherent to
2470 this operation, so we defer the open until read time. */
2472 if (dir_find_handle != INVALID_HANDLE_VALUE)
2473 return NULL;
2474 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
2475 return NULL;
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))
2482 wnet_enum_handle = open_unc_volume (filename);
2483 if (wnet_enum_handle == INVALID_HANDLE_VALUE)
2484 return NULL;
2487 if (!(dirp = (DIR *) malloc (sizeof (DIR))))
2488 return NULL;
2490 dirp->dd_fd = 0;
2491 dirp->dd_loc = 0;
2492 dirp->dd_size = 0;
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);
2501 return dirp;
2504 void
2505 closedir (DIR *dirp)
2507 /* If we have a find-handle open, close it. */
2508 if (dir_find_handle != INVALID_HANDLE_VALUE)
2510 FindClose (dir_find_handle);
2511 dir_find_handle = INVALID_HANDLE_VALUE;
2513 else if (wnet_enum_handle != INVALID_HANDLE_VALUE)
2515 close_unc_volume (wnet_enum_handle);
2516 wnet_enum_handle = INVALID_HANDLE_VALUE;
2518 xfree ((char *) dirp);
2521 struct dirent *
2522 readdir (DIR *dirp)
2524 int downcase = !NILP (Vw32_downcase_file_names);
2526 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
2528 if (!read_unc_volume (wnet_enum_handle,
2529 dir_find_data.cFileName,
2530 MAX_PATH))
2531 return NULL;
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)
2536 char filename[MAXNAMLEN + 3];
2537 int ln;
2539 strcpy (filename, dir_pathname);
2540 ln = strlen (filename) - 1;
2541 if (!IS_DIRECTORY_SEP (filename[ln]))
2542 strcat (filename, "\\");
2543 strcat (filename, "*");
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);
2550 if (dir_find_handle == INVALID_HANDLE_VALUE)
2551 return NULL;
2553 else
2555 if (!FindNextFile (dir_find_handle, &dir_find_data))
2556 return NULL;
2559 /* Emacs never uses this value, so don't bother making it match
2560 value returned by stat(). */
2561 dir_static.d_ino = 1;
2563 strcpy (dir_static.d_name, dir_find_data.cFileName);
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, "?"))
2571 strcpy (dir_static.d_name, dir_find_data.cAlternateFileName);
2572 downcase = 1; /* 8+3 aliases are returned in all caps */
2574 dir_static.d_namlen = strlen (dir_static.d_name);
2575 dir_static.d_reclen = sizeof (struct dirent) - MAXNAMLEN + 3 +
2576 dir_static.d_namlen - dir_static.d_namlen % 4;
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, "?"))
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;
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)
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);
2604 return &dir_static;
2607 static HANDLE
2608 open_unc_volume (const char *path)
2610 NETRESOURCE nr;
2611 HANDLE henum;
2612 int result;
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;
2623 result = WNetOpenEnum (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
2624 RESOURCEUSAGE_CONNECTABLE, &nr, &henum);
2626 if (result == NO_ERROR)
2627 return henum;
2628 else
2629 return INVALID_HANDLE_VALUE;
2632 static char *
2633 read_unc_volume (HANDLE henum, char *readbuf, int size)
2635 DWORD count;
2636 int result;
2637 DWORD bufsize = 512;
2638 char *buffer;
2639 char *ptr;
2641 count = 1;
2642 buffer = alloca (bufsize);
2643 result = WNetEnumResource (henum, &count, buffer, &bufsize);
2644 if (result != NO_ERROR)
2645 return NULL;
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++;
2653 strncpy (readbuf, ptr, size);
2654 return readbuf;
2657 static void
2658 close_unc_volume (HANDLE henum)
2660 if (henum != INVALID_HANDLE_VALUE)
2661 WNetCloseEnum (henum);
2664 static DWORD
2665 unc_volume_file_attributes (const char *path)
2667 HANDLE henum;
2668 DWORD attrs;
2670 henum = open_unc_volume (path);
2671 if (henum == INVALID_HANDLE_VALUE)
2672 return -1;
2674 attrs = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY;
2676 close_unc_volume (henum);
2678 return attrs;
2681 /* Ensure a network connection is authenticated. */
2682 static void
2683 logon_network_drive (const char *path)
2685 NETRESOURCE resource;
2686 char share[MAX_PATH];
2687 int i, n_slashes;
2688 char drive[4];
2689 UINT drvtype;
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
2697 drive[0] = path[0];
2698 drive[1] = ':';
2699 drive[2] = '\\';
2700 drive[3] = '\0';
2701 drvtype = GetDriveType (drive);
2704 /* Only logon to networked drives. */
2705 if (drvtype != DRIVE_REMOTE)
2706 return;
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++)
2713 if (IS_DIRECTORY_SEP (share[i]) && ++n_slashes > 3)
2715 share[i] = '\0';
2716 break;
2720 resource.dwType = RESOURCETYPE_DISK;
2721 resource.lpLocalName = NULL;
2722 resource.lpRemoteName = share;
2723 resource.lpProvider = NULL;
2725 WNetAddConnection2 (&resource, NULL, NULL, CONNECT_INTERACTIVE);
2728 /* Emulate faccessat(2). */
2730 faccessat (int dirfd, const char * path, int mode, int flags)
2732 DWORD attributes;
2734 if (dirfd != AT_FDCWD
2735 && !(IS_DIRECTORY_SEP (path[0])
2736 || IS_DEVICE_SEP (path[1])))
2738 errno = EBADF;
2739 return -1;
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);
2753 if ((attributes = GetFileAttributes (path)) == -1)
2755 DWORD w32err = GetLastError ();
2757 switch (w32err)
2759 case ERROR_INVALID_NAME:
2760 case ERROR_BAD_PATHNAME:
2761 if (is_unc_volume (path))
2763 attributes = unc_volume_file_attributes (path);
2764 if (attributes == -1)
2766 errno = EACCES;
2767 return -1;
2769 break;
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;
2780 return -1;
2782 if ((mode & X_OK) != 0
2783 && !(is_exec (path) || (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0))
2785 errno = EACCES;
2786 return -1;
2788 if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0)
2790 errno = EACCES;
2791 return -1;
2793 if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
2795 errno = EACCES;
2796 return -1;
2798 return 0;
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. */
2807 sys_chdir (const char * path)
2809 return _chdir (map_w32_filename (path, NULL));
2813 sys_chmod (const char * path, int mode)
2815 path = chase_symlinks (map_w32_filename (path, NULL));
2816 return _chmod (path, mode);
2820 sys_chown (const char *path, uid_t owner, gid_t group)
2822 if (sys_chmod (path, S_IREAD) == -1) /* check if file exists */
2823 return -1;
2824 return 0;
2828 sys_creat (const char * path, int mode)
2830 return _creat (map_w32_filename (path, NULL), mode);
2833 FILE *
2834 sys_fopen (const char * path, const char * mode)
2836 int fd;
2837 int oflag;
2838 const char * mode_save = mode;
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. */
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;
2851 /* Only do simplistic option parsing. */
2852 while (*++mode)
2853 if (mode[0] == '+')
2855 oflag &= ~(O_RDONLY | O_WRONLY);
2856 oflag |= O_RDWR;
2858 else if (mode[0] == 'b')
2860 oflag &= ~O_TEXT;
2861 oflag |= O_BINARY;
2863 else if (mode[0] == 't')
2865 oflag &= ~O_BINARY;
2866 oflag |= O_TEXT;
2868 else break;
2870 fd = _open (map_w32_filename (path, NULL), oflag | _O_NOINHERIT, 0644);
2871 if (fd < 0)
2872 return NULL;
2874 return _fdopen (fd, mode_save);
2877 /* This only works on NTFS volumes, but is useful to have. */
2879 sys_link (const char * old, const char * new)
2881 HANDLE fileh;
2882 int result = -1;
2883 char oldname[MAX_PATH], newname[MAX_PATH];
2885 if (old == NULL || new == NULL)
2887 errno = ENOENT;
2888 return -1;
2891 strcpy (oldname, map_w32_filename (old, NULL));
2892 strcpy (newname, map_w32_filename (new, NULL));
2894 fileh = CreateFile (oldname, 0, 0, NULL, OPEN_EXISTING,
2895 FILE_FLAG_BACKUP_SEMANTICS, NULL);
2896 if (fileh != INVALID_HANDLE_VALUE)
2898 int wlen;
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. */
2907 struct {
2908 WIN32_STREAM_ID wid;
2909 WCHAR wbuffer[MAX_PATH]; /* extra space for link name */
2910 } data;
2912 wlen = MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, newname, -1,
2913 data.wid.cStreamName, MAX_PATH);
2914 if (wlen > 0)
2916 LPVOID context = NULL;
2917 DWORD wbytes = 0;
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;
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))
2931 /* succeeded */
2932 result = 0;
2934 else
2936 /* Should try mapping GetLastError to errno; for now just
2937 indicate a general error (eg. links not supported). */
2938 errno = EINVAL; // perhaps EMLINK?
2942 CloseHandle (fileh);
2944 else
2945 errno = ENOENT;
2947 return result;
2951 sys_mkdir (const char * path)
2953 return _mkdir (map_w32_filename (path, NULL));
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.
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)
2968 char * p;
2969 int i;
2970 unsigned uid = GetCurrentThreadId ();
2971 static char first_char[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
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)
2980 p[0] = '0' + uid % 10;
2981 uid /= 10;
2984 if (i < 0 && p[0] == 'X')
2986 i = 0;
2989 int save_errno = errno;
2990 p[0] = first_char[i];
2991 if (faccessat (AT_FDCWD, template, F_OK, AT_EACCESS) < 0)
2993 errno = save_errno;
2994 return template;
2997 while (++i < sizeof (first_char));
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;
3007 sys_open (const char * path, int oflag, int mode)
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);
3020 sys_rename (const char * oldname, const char * newname)
3022 BOOL result;
3023 char temp[MAX_PATH];
3024 int newname_dev;
3025 int oldname_dev;
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.
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.
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. */
3040 strcpy (temp, map_w32_filename (oldname, NULL));
3042 /* volume_info is set indirectly by map_w32_filename. */
3043 oldname_dev = volume_info.serialnum;
3045 if (os_subtype == OS_9X)
3047 char * o;
3048 char * p;
3049 int i = 0;
3051 oldname = map_w32_filename (oldname, NULL);
3052 if ((o = strrchr (oldname, '\\')))
3053 o++;
3054 else
3055 o = (char *) oldname;
3057 if ((p = strrchr (temp, '\\')))
3058 p++;
3059 else
3060 p = temp;
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);
3070 /* This loop must surely terminate! */
3071 while (result < 0 && errno == EEXIST);
3072 if (result < 0)
3073 return -1;
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).
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.) */
3087 newname = map_w32_filename (newname, NULL);
3089 /* volume_info is set indirectly by map_w32_filename. */
3090 newname_dev = volume_info.serialnum;
3092 result = rename (temp, newname);
3094 if (result < 0)
3096 DWORD w32err = GetLastError ();
3098 if (errno == EACCES
3099 && newname_dev != oldname_dev)
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;
3108 if ((attributes = GetFileAttributes (temp)) != -1
3109 && (attributes & FILE_ATTRIBUTE_DIRECTORY))
3110 errno = EXDEV;
3112 else if (errno == EEXIST)
3114 if (_chmod (newname, 0666) != 0)
3115 return result;
3116 if (_unlink (newname) != 0)
3117 return result;
3118 result = rename (temp, newname);
3120 else if (w32err == ERROR_PRIVILEGE_NOT_HELD
3121 && is_symlink (temp))
3123 /* This is Windows prohibiting the user from creating a
3124 symlink in another place, since that requires
3125 privileges. */
3126 errno = EPERM;
3130 return result;
3134 sys_rmdir (const char * path)
3136 return _rmdir (map_w32_filename (path, NULL));
3140 sys_unlink (const char * path)
3142 path = map_w32_filename (path, NULL);
3144 /* On Unix, unlink works without write permission. */
3145 _chmod (path, 0666);
3146 return _unlink (path);
3149 static FILETIME utc_base_ft;
3150 static ULONGLONG utc_base; /* In 100ns units */
3151 static int init = 0;
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)
3161 static void
3162 initialize_utc_base (void)
3164 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
3165 SYSTEMTIME st;
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;
3175 SystemTimeToFileTime (&st, &utc_base_ft);
3176 FILETIME_TO_U64 (utc_base, utc_base_ft);
3179 static time_t
3180 convert_time (FILETIME ft)
3182 ULONGLONG tmp;
3184 if (!init)
3186 initialize_utc_base ();
3187 init = 1;
3190 if (CompareFileTime (&ft, &utc_base_ft) < 0)
3191 return 0;
3193 FILETIME_TO_U64 (tmp, ft);
3194 return (time_t) ((tmp - utc_base) / 10000000L);
3197 static void
3198 convert_from_time_t (time_t time, FILETIME * pft)
3200 ULARGE_INTEGER tmp;
3202 if (!init)
3204 initialize_utc_base ();
3205 init = 1;
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;
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). */
3221 /* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
3222 static unsigned
3223 hashval (const unsigned char * str)
3225 unsigned h = 0;
3226 while (*str)
3228 h = (h << 4) + *str++;
3229 h ^= (h >> 28);
3231 return h;
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)
3239 char fullname[ MAX_PATH ];
3240 char * p;
3241 unsigned hash;
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 ();
3249 parse_root (fullname, &p);
3250 /* Normal W32 filesystems are still case insensitive. */
3251 _strlwr (p);
3252 return hashval (p);
3255 #endif
3257 static PSECURITY_DESCRIPTOR
3258 get_file_security_desc_by_handle (HANDLE h)
3260 PSECURITY_DESCRIPTOR psd = NULL;
3261 DWORD err;
3262 SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION
3263 | GROUP_SECURITY_INFORMATION /* | DACL_SECURITY_INFORMATION */ ;
3265 err = get_security_info (h, SE_FILE_OBJECT, si,
3266 NULL, NULL, NULL, NULL, &psd);
3267 if (err != ERROR_SUCCESS)
3268 return NULL;
3270 return psd;
3273 static PSECURITY_DESCRIPTOR
3274 get_file_security_desc_by_name (const char *fname)
3276 PSECURITY_DESCRIPTOR psd = NULL;
3277 DWORD sd_len, err;
3278 SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION
3279 | GROUP_SECURITY_INFORMATION /* | DACL_SECURITY_INFORMATION */ ;
3281 if (!get_file_security (fname, si, psd, 0, &sd_len))
3283 err = GetLastError ();
3284 if (err != ERROR_INSUFFICIENT_BUFFER)
3285 return NULL;
3288 psd = xmalloc (sd_len);
3289 if (!get_file_security (fname, si, psd, sd_len, &sd_len))
3291 xfree (psd);
3292 return NULL;
3295 return psd;
3298 static DWORD
3299 get_rid (PSID sid)
3301 unsigned n_subauthorities;
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);
3311 /* Caching SID and account values for faster lokup. */
3313 #ifdef __GNUC__
3314 # define FLEXIBLE_ARRAY_MEMBER
3315 #else
3316 # define FLEXIBLE_ARRAY_MEMBER 1
3317 #endif
3319 struct w32_id {
3320 unsigned rid;
3321 struct w32_id *next;
3322 char name[GNLEN+1];
3323 unsigned char sid[FLEXIBLE_ARRAY_MEMBER];
3326 static struct w32_id *w32_idlist;
3328 static int
3329 w32_cached_id (PSID sid, unsigned *id, char *name)
3331 struct w32_id *tail, *found;
3333 for (found = NULL, tail = w32_idlist; tail; tail = tail->next)
3335 if (equal_sid ((PSID)tail->sid, sid))
3337 found = tail;
3338 break;
3341 if (found)
3343 *id = found->rid;
3344 strcpy (name, found->name);
3345 return 1;
3347 else
3348 return 0;
3351 static void
3352 w32_add_to_cache (PSID sid, unsigned id, char *name)
3354 DWORD sid_len;
3355 struct w32_id *new_entry;
3357 /* We don't want to leave behind stale cache from when Emacs was
3358 dumped. */
3359 if (initialized)
3361 sid_len = get_length_sid (sid);
3362 new_entry = xmalloc (offsetof (struct w32_id, sid) + sid_len);
3363 if (new_entry)
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;
3374 #define UID 1
3375 #define GID 2
3377 static int
3378 get_name_and_id (PSECURITY_DESCRIPTOR psd, const char *fname,
3379 unsigned *id, char *nm, int what)
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;
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;
3400 if (!result || !is_valid_sid (sid))
3401 use_dflt = 1;
3402 else if (!w32_cached_id (sid, id, nm))
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')
3409 const char *s;
3410 char *p;
3412 for (s = fname + 2, p = machine;
3413 *s && !IS_DIRECTORY_SEP (*s); s++, p++)
3414 *p = *s;
3415 *p = '\0';
3416 mp = machine;
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
3425 *id = get_rid (sid);
3426 strcpy (nm, name);
3427 w32_add_to_cache (sid, *id, name);
3430 return use_dflt;
3433 static void
3434 get_file_owner_and_group (PSECURITY_DESCRIPTOR psd,
3435 const char *fname,
3436 struct stat *st)
3438 int dflt_usr = 0, dflt_grp = 0;
3440 if (!psd)
3442 dflt_usr = 1;
3443 dflt_grp = 1;
3445 else
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;
3452 /* Consider files to belong to current user/group, if we cannot get
3453 more accurate information. */
3454 if (dflt_usr)
3456 st->st_uid = dflt_passwd.pw_uid;
3457 strcpy (st->st_uname, dflt_passwd.pw_name);
3459 if (dflt_grp)
3461 st->st_gid = dflt_passwd.pw_gid;
3462 strcpy (st->st_gname, dflt_group.gr_name);
3466 /* Return non-zero if NAME is a potentially slow filesystem. */
3468 is_slow_fs (const char *name)
3470 char drive_root[4];
3471 UINT devtype;
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
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);
3485 return !(devtype == DRIVE_FIXED || devtype == DRIVE_RAMDISK);
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. */
3492 static int
3493 stat_worker (const char * path, struct stat * buf, int follow_symlinks)
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;
3509 if (path == NULL || buf == NULL)
3511 errno = EFAULT;
3512 return -1;
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, "*?|<>\""))
3523 errno = ENOENT;
3524 return -1;
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);
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);
3538 /* Plan A: Open the file and get all the necessary information via
3539 the resulting handle. This solves several issues in one blow:
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
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).
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))
3562 BY_HANDLE_FILE_INFORMATION info;
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;
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;
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))
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;
3604 else
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. */
3618 /* w32err is assigned so one could put a breakpoint here and
3619 examine its value, when GetFileInformationByHandle
3620 fails. */
3621 DWORD w32err = GetLastError ();
3623 switch (w32err)
3625 case ERROR_FILE_NOT_FOUND: /* can this ever happen? */
3626 errno = ENOENT;
3627 return -1;
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
3640 DWORD ftype = GetFileType (fh);
3642 switch (ftype)
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;
3656 /* We produce the fallback owner and group data, based on the
3657 current user that runs Emacs, in the following cases:
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)
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)
3671 get_file_owner_and_group (psd, name, buf);
3672 LocalFree (psd);
3674 else if (is_windows_9x () == TRUE)
3675 get_file_owner_and_group (NULL, name, buf);
3676 else if (!(is_a_symlink && follow_symlinks))
3678 psd = get_file_security_desc_by_name (name);
3679 get_file_owner_and_group (psd, name, buf);
3680 xfree (psd);
3682 else
3683 get_file_owner_and_group (NULL, name, buf);
3684 CloseHandle (fh);
3686 else
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.
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));
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';
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))
3721 fattrs = unc_volume_file_attributes (name);
3722 if (fattrs == -1)
3723 return -1;
3725 ctime = atime = wtime = utc_base_ft;
3727 else if (rootdir)
3729 if (!IS_DIRECTORY_SEP (name[len-1]))
3730 strcat (name, "\\");
3731 if (GetDriveType (name) < 2)
3733 errno = ENOENT;
3734 return -1;
3737 fattrs = FILE_ATTRIBUTE_DIRECTORY;
3738 ctime = atime = wtime = utc_base_ft;
3740 else
3742 if (IS_DIRECTORY_SEP (name[len-1]))
3743 name[len - 1] = 0;
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)
3757 /* This was the last entry returned by readdir. */
3758 wfd = dir_find_data;
3760 else
3762 logon_network_drive (name);
3764 fh = FindFirstFile (name, &wfd);
3765 if (fh == INVALID_HANDLE_VALUE)
3767 errno = ENOENT;
3768 return -1;
3770 FindClose (fh);
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;
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;
3791 get_file_owner_and_group (NULL, name, buf);
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)
3800 /* For want of something better, try to make everything unique. */
3801 static DWORD gen_num = 0;
3802 fake_inode = ++gen_num;
3804 #endif
3806 buf->st_ino = fake_inode;
3808 buf->st_dev = serialnum;
3809 buf->st_rdev = serialnum;
3811 buf->st_size = fs_high;
3812 buf->st_size <<= 32;
3813 buf->st_size += fs_low;
3814 buf->st_nlink = nlinks;
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;
3823 /* determine rwx permissions */
3824 if (is_a_symlink && !follow_symlinks)
3825 permission = S_IREAD | S_IWRITE | S_IEXEC; /* Posix expectations */
3826 else
3828 if (fattrs & FILE_ATTRIBUTE_READONLY)
3829 permission = S_IREAD;
3830 else
3831 permission = S_IREAD | S_IWRITE;
3833 if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
3834 permission |= S_IEXEC;
3835 else if (is_exec (name))
3836 permission |= S_IEXEC;
3839 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
3841 return 0;
3845 stat (const char * path, struct stat * buf)
3847 return stat_worker (path, buf, 1);
3851 lstat (const char * path, struct stat * buf)
3853 return stat_worker (path, buf, 0);
3856 /* Provide fstat and utime as well as stat for consistent handling of
3857 file timestamps. */
3859 fstat (int desc, struct stat * buf)
3861 HANDLE fh = (HANDLE) _get_osfhandle (desc);
3862 BY_HANDLE_FILE_INFORMATION info;
3863 unsigned __int64 fake_inode;
3864 int permission;
3866 switch (GetFileType (fh) & ~FILE_TYPE_REMOTE)
3868 case FILE_TYPE_DISK:
3869 buf->st_mode = S_IFREG;
3870 if (!GetFileInformationByHandle (fh, &info))
3872 errno = EACCES;
3873 return -1;
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;
3891 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
3892 buf->st_mode = S_IFDIR;
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;
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;
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);
3918 buf->st_dev = info.dwVolumeSerialNumber;
3919 buf->st_rdev = info.dwVolumeSerialNumber;
3921 buf->st_size = info.nFileSizeHigh;
3922 buf->st_size <<= 32;
3923 buf->st_size += info.nFileSizeLow;
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;
3932 /* determine rwx permissions */
3933 if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
3934 permission = S_IREAD;
3935 else
3936 permission = S_IREAD | S_IWRITE;
3938 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
3939 permission |= S_IEXEC;
3940 else
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
3953 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
3955 return 0;
3959 utime (const char *name, struct utimbuf *times)
3961 struct utimbuf deftime;
3962 HANDLE fh;
3963 FILETIME mtime;
3964 FILETIME atime;
3966 if (times == NULL)
3968 deftime.modtime = deftime.actime = time (NULL);
3969 times = &deftime;
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)
3981 convert_from_time_t (times->actime, &atime);
3982 convert_from_time_t (times->modtime, &mtime);
3983 if (!SetFileTime (fh, NULL, &atime, &mtime))
3985 CloseHandle (fh);
3986 errno = EACCES;
3987 return -1;
3989 CloseHandle (fh);
3991 else
3993 errno = EINVAL;
3994 return -1;
3996 return 0;
4000 /* Symlink-related functions. */
4001 #ifndef SYMBOLIC_LINK_FLAG_DIRECTORY
4002 #define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1
4003 #endif
4006 symlink (char const *filename, char const *linkname)
4008 char linkfn[MAX_PATH], *tgtfn;
4009 DWORD flags = 0;
4010 int dir_access, filename_ends_in_slash;
4012 /* Diagnostics follows Posix as much as possible. */
4013 if (filename == NULL || linkname == NULL)
4015 errno = EFAULT;
4016 return -1;
4018 if (!*filename)
4020 errno = ENOENT;
4021 return -1;
4023 if (strlen (filename) > MAX_PATH || strlen (linkname) > MAX_PATH)
4025 errno = ENAMETOOLONG;
4026 return -1;
4029 strcpy (linkfn, map_w32_filename (linkname, NULL));
4030 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) == 0)
4032 errno = EPERM;
4033 return -1;
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])))
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);
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);
4058 else
4059 dir_access = faccessat (AT_FDCWD, filename, D_OK, AT_EACCESS);
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;
4070 tgtfn = (char *)map_w32_filename (filename, NULL);
4071 if (filename_ends_in_slash)
4072 tgtfn[strlen (tgtfn) - 1] = '\0';
4074 errno = 0;
4075 if (!create_symbolic_link (linkfn, tgtfn, flags))
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)
4081 DWORD w32err = GetLastError ();
4083 switch (w32err)
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;
4115 return -1;
4117 return 0;
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.
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)
4135 DWORD attrs;
4136 WIN32_FIND_DATA wfd;
4137 HANDLE fh;
4139 attrs = GetFileAttributes (filename);
4140 if (attrs == -1)
4142 DWORD w32err = GetLastError ();
4144 switch (w32err)
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;
4157 return 0;
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;
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)
4179 const char *path;
4180 TOKEN_PRIVILEGES privs;
4181 int restore_privs = 0;
4182 HANDLE sh;
4183 ssize_t retval;
4185 if (name == NULL)
4187 errno = EFAULT;
4188 return -1;
4190 if (!*name)
4192 errno = ENOENT;
4193 return -1;
4196 path = map_w32_filename (name, NULL);
4198 if (strlen (path) > MAX_PATH)
4200 errno = ENAMETOOLONG;
4201 return -1;
4204 errno = 0;
4205 if (is_windows_9x () == TRUE
4206 || (volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) == 0
4207 || !is_symlink (path))
4209 if (!errno)
4210 errno = EINVAL; /* not a symlink */
4211 return -1;
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. */
4221 retval = -1; /* not too optimistic, are we? */
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)
4233 BYTE reparse_buf[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
4234 REPARSE_DATA_BUFFER *reparse_data = (REPARSE_DATA_BUFFER *)&reparse_buf[0];
4235 DWORD retbytes;
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
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);
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 */
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)
4269 /* WideCharToMultiByte failed. */
4270 DWORD w32err1 = GetLastError ();
4272 switch (w32err1)
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;
4288 else
4290 size_t size_to_copy = buf_size;
4291 BYTE *p = lname;
4292 BYTE *pend = p + lname_len;
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)
4300 if (*p == '\\')
4301 *p = '/';
4302 ++p;
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;
4318 CloseHandle (sh);
4320 else
4322 /* CreateFile failed. */
4323 DWORD w32err2 = GetLastError ();
4325 switch (w32err2)
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;
4340 if (restore_privs)
4342 restore_privilege (&privs);
4343 revert_to_self ();
4346 return retval;
4349 /* If FILE is a symlink, return its target (stored in a static
4350 buffer); otherwise return FILE.
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.
4361 Note: This function can set errno even if it succeeds.
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)
4372 static char target[MAX_PATH];
4373 char link[MAX_PATH];
4374 ssize_t res, link_len;
4375 int loop_count = 0;
4377 if (is_windows_9x () == TRUE || !is_symlink (file))
4378 return (char *)file;
4380 if ((link_len = GetFullPathName (file, MAX_PATH, link, NULL)) == 0)
4381 return (char *)file;
4383 target[0] = '\0';
4384 do {
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';
4391 res = readlink (link, target, MAX_PATH);
4392 if (res > 0)
4394 target[res] = '\0';
4395 if (!(IS_DEVICE_SEP (target[1])
4396 || (IS_DIRECTORY_SEP (target[0]) && IS_DIRECTORY_SEP (target[1]))))
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;
4402 while (p > link && !IS_ANY_SEP (p[-1]))
4403 p--;
4404 strcpy (p, target);
4405 strcpy (target, link);
4407 /* Resolve any "." and ".." to get a fully-qualified file name
4408 in link[] again. */
4409 link_len = GetFullPathName (target, MAX_PATH, link, NULL);
4411 } while (res > 0 && link_len > 0 && ++loop_count <= 100);
4413 if (loop_count > 100)
4414 errno = ELOOP;
4416 if (target[0] == '\0') /* not a single call to readlink succeeded */
4417 return (char *)file;
4418 return target;
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))
4431 char linkname[MAX_PATH];
4432 ssize_t link_size;
4434 if (fd != AT_FDCWD)
4436 errno = EINVAL;
4437 return NULL;
4440 link_size = preadlinkat (fd, filename, linkname, sizeof(linkname));
4442 if (link_size > 0)
4444 char *retval = buffer;
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);
4452 return retval;
4454 return NULL;
4457 ssize_t
4458 careadlinkatcwd (int fd, char const *filename, char *buffer,
4459 size_t buffer_size)
4461 (void) fd;
4462 return readlink (filename, buffer, buffer_size);
4466 /* Support for browsing other processes and their attributes. See
4467 process.c for the Lisp bindings. */
4469 /* Helper wrapper functions. */
4471 static HANDLE WINAPI
4472 create_toolhelp32_snapshot (DWORD Flags, DWORD Ignored)
4474 static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot = NULL;
4476 if (g_b_init_create_toolhelp32_snapshot == 0)
4478 g_b_init_create_toolhelp32_snapshot = 1;
4479 s_pfn_Create_Toolhelp32_Snapshot = (CreateToolhelp32Snapshot_Proc)
4480 GetProcAddress (GetModuleHandle ("kernel32.dll"),
4481 "CreateToolhelp32Snapshot");
4483 if (s_pfn_Create_Toolhelp32_Snapshot == NULL)
4485 return INVALID_HANDLE_VALUE;
4487 return (s_pfn_Create_Toolhelp32_Snapshot (Flags, Ignored));
4490 static BOOL WINAPI
4491 process32_first (HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
4493 static Process32First_Proc s_pfn_Process32_First = NULL;
4495 if (g_b_init_process32_first == 0)
4497 g_b_init_process32_first = 1;
4498 s_pfn_Process32_First = (Process32First_Proc)
4499 GetProcAddress (GetModuleHandle ("kernel32.dll"),
4500 "Process32First");
4502 if (s_pfn_Process32_First == NULL)
4504 return FALSE;
4506 return (s_pfn_Process32_First (hSnapshot, lppe));
4509 static BOOL WINAPI
4510 process32_next (HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
4512 static Process32Next_Proc s_pfn_Process32_Next = NULL;
4514 if (g_b_init_process32_next == 0)
4516 g_b_init_process32_next = 1;
4517 s_pfn_Process32_Next = (Process32Next_Proc)
4518 GetProcAddress (GetModuleHandle ("kernel32.dll"),
4519 "Process32Next");
4521 if (s_pfn_Process32_Next == NULL)
4523 return FALSE;
4525 return (s_pfn_Process32_Next (hSnapshot, lppe));
4528 static BOOL WINAPI
4529 open_thread_token (HANDLE ThreadHandle,
4530 DWORD DesiredAccess,
4531 BOOL OpenAsSelf,
4532 PHANDLE TokenHandle)
4534 static OpenThreadToken_Proc s_pfn_Open_Thread_Token = NULL;
4535 HMODULE hm_advapi32 = NULL;
4536 if (is_windows_9x () == TRUE)
4538 SetLastError (ERROR_NOT_SUPPORTED);
4539 return FALSE;
4541 if (g_b_init_open_thread_token == 0)
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");
4548 if (s_pfn_Open_Thread_Token == NULL)
4550 SetLastError (ERROR_NOT_SUPPORTED);
4551 return FALSE;
4553 return (
4554 s_pfn_Open_Thread_Token (
4555 ThreadHandle,
4556 DesiredAccess,
4557 OpenAsSelf,
4558 TokenHandle)
4562 static BOOL WINAPI
4563 impersonate_self (SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
4565 static ImpersonateSelf_Proc s_pfn_Impersonate_Self = NULL;
4566 HMODULE hm_advapi32 = NULL;
4567 if (is_windows_9x () == TRUE)
4569 return FALSE;
4571 if (g_b_init_impersonate_self == 0)
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");
4578 if (s_pfn_Impersonate_Self == NULL)
4580 return FALSE;
4582 return s_pfn_Impersonate_Self (ImpersonationLevel);
4585 static BOOL WINAPI
4586 revert_to_self (void)
4588 static RevertToSelf_Proc s_pfn_Revert_To_Self = NULL;
4589 HMODULE hm_advapi32 = NULL;
4590 if (is_windows_9x () == TRUE)
4592 return FALSE;
4594 if (g_b_init_revert_to_self == 0)
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");
4601 if (s_pfn_Revert_To_Self == NULL)
4603 return FALSE;
4605 return s_pfn_Revert_To_Self ();
4608 static BOOL WINAPI
4609 get_process_memory_info (HANDLE h_proc,
4610 PPROCESS_MEMORY_COUNTERS mem_counters,
4611 DWORD bufsize)
4613 static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info = NULL;
4614 HMODULE hm_psapi = NULL;
4615 if (is_windows_9x () == TRUE)
4617 return FALSE;
4619 if (g_b_init_get_process_memory_info == 0)
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");
4627 if (s_pfn_Get_Process_Memory_Info == NULL)
4629 return FALSE;
4631 return s_pfn_Get_Process_Memory_Info (h_proc, mem_counters, bufsize);
4634 static BOOL WINAPI
4635 get_process_working_set_size (HANDLE h_proc,
4636 DWORD *minrss,
4637 DWORD *maxrss)
4639 static GetProcessWorkingSetSize_Proc
4640 s_pfn_Get_Process_Working_Set_Size = NULL;
4642 if (is_windows_9x () == TRUE)
4644 return FALSE;
4646 if (g_b_init_get_process_working_set_size == 0)
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");
4653 if (s_pfn_Get_Process_Working_Set_Size == NULL)
4655 return FALSE;
4657 return s_pfn_Get_Process_Working_Set_Size (h_proc, minrss, maxrss);
4660 static BOOL WINAPI
4661 global_memory_status (MEMORYSTATUS *buf)
4663 static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status = NULL;
4665 if (is_windows_9x () == TRUE)
4667 return FALSE;
4669 if (g_b_init_global_memory_status == 0)
4671 g_b_init_global_memory_status = 1;
4672 s_pfn_Global_Memory_Status = (GlobalMemoryStatus_Proc)
4673 GetProcAddress (GetModuleHandle ("kernel32.dll"),
4674 "GlobalMemoryStatus");
4676 if (s_pfn_Global_Memory_Status == NULL)
4678 return FALSE;
4680 return s_pfn_Global_Memory_Status (buf);
4683 static BOOL WINAPI
4684 global_memory_status_ex (MEMORY_STATUS_EX *buf)
4686 static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex = NULL;
4688 if (is_windows_9x () == TRUE)
4690 return FALSE;
4692 if (g_b_init_global_memory_status_ex == 0)
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");
4699 if (s_pfn_Global_Memory_Status_Ex == NULL)
4701 return FALSE;
4703 return s_pfn_Global_Memory_Status_Ex (buf);
4706 Lisp_Object
4707 list_system_processes (void)
4709 struct gcpro gcpro1;
4710 Lisp_Object proclist = Qnil;
4711 HANDLE h_snapshot;
4713 h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
4715 if (h_snapshot != INVALID_HANDLE_VALUE)
4717 PROCESSENTRY32 proc_entry;
4718 DWORD proc_id;
4719 BOOL res;
4721 GCPRO1 (proclist);
4723 proc_entry.dwSize = sizeof (PROCESSENTRY32);
4724 for (res = process32_first (h_snapshot, &proc_entry); res;
4725 res = process32_next (h_snapshot, &proc_entry))
4727 proc_id = proc_entry.th32ProcessID;
4728 proclist = Fcons (make_fixnum_or_float (proc_id), proclist);
4731 CloseHandle (h_snapshot);
4732 UNGCPRO;
4733 proclist = Fnreverse (proclist);
4736 return proclist;
4739 static int
4740 enable_privilege (LPCTSTR priv_name, BOOL enable_p, TOKEN_PRIVILEGES *old_priv)
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;
4750 res = open_thread_token (h_thread,
4751 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
4752 FALSE, &h_token);
4753 if (!res && GetLastError () == ERROR_NO_TOKEN)
4755 if (impersonate_self (SecurityImpersonation))
4756 res = open_thread_token (h_thread,
4757 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
4758 FALSE, &h_token);
4760 if (res)
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;
4770 if (h_token)
4771 CloseHandle (h_token);
4773 return ret_val;
4776 static int
4777 restore_privilege (TOKEN_PRIVILEGES *priv)
4779 DWORD priv_size = sizeof (*priv);
4780 HANDLE h_token = NULL;
4781 int ret_val = 0;
4783 if (open_thread_token (GetCurrentThread (),
4784 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
4785 FALSE, &h_token))
4787 if (AdjustTokenPrivileges (h_token, FALSE, priv, priv_size, NULL, NULL)
4788 && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
4789 ret_val = 1;
4791 if (h_token)
4792 CloseHandle (h_token);
4794 return ret_val;
4797 static Lisp_Object
4798 ltime (ULONGLONG time_100ns)
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));
4808 #define U64_TO_LISP_TIME(time) ltime (time)
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)
4815 FILETIME ft_creation, ft_exit, ft_kernel, ft_user, ft_current;
4816 ULONGLONG tem1, tem2, tem3, tem;
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;
4824 GetSystemTimeAsFileTime (&ft_current);
4826 FILETIME_TO_U64 (tem1, ft_kernel);
4827 *stime = U64_TO_LISP_TIME (tem1);
4829 FILETIME_TO_U64 (tem2, ft_user);
4830 *utime = U64_TO_LISP_TIME (tem2);
4832 tem3 = tem1 + tem2;
4833 *ttime = U64_TO_LISP_TIME (tem3);
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);
4841 if (tem)
4843 FILETIME_TO_U64 (tem3, ft_current);
4844 tem = (tem3 - utc_base) - tem;
4846 *etime = U64_TO_LISP_TIME (tem);
4848 if (tem)
4850 *pcpu = 100.0 * (tem1 + tem2) / tem;
4851 if (*pcpu > 100)
4852 *pcpu = 100.0;
4854 else
4855 *pcpu = 0;
4857 return 1;
4860 Lisp_Object
4861 system_process_attributes (Lisp_Object pid)
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;
4890 CHECK_NUMBER_OR_FLOAT (pid);
4891 proc_id = FLOATP (pid) ? XFLOAT_DATA (pid) : XINT (pid);
4893 h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
4895 GCPRO3 (attrs, decoded_cmd, tem);
4897 if (h_snapshot != INVALID_HANDLE_VALUE)
4899 PROCESSENTRY32 pe;
4900 BOOL res;
4902 pe.dwSize = sizeof (PROCESSENTRY32);
4903 for (res = process32_first (h_snapshot, &pe); res;
4904 res = process32_next (h_snapshot, &pe))
4906 if (proc_id == pe.th32ProcessID)
4908 if (proc_id == 0)
4909 decoded_cmd = build_string ("Idle");
4910 else
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);
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;
4934 CloseHandle (h_snapshot);
4937 if (!found_proc)
4939 UNGCPRO;
4940 return Qnil;
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)
4949 TOKEN_PRIVILEGES priv_current;
4951 if (enable_privilege (SE_DEBUG_NAME, TRUE, &priv_current))
4953 h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
4954 FALSE, proc_id);
4955 restore_privilege (&priv_current);
4956 revert_to_self ();
4959 if (h_proc)
4961 result = open_process_token (h_proc, TOKEN_QUERY, &token);
4962 if (result)
4964 result = get_token_information (token, TokenUser, NULL, 0, &blen);
4965 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
4967 buf = xmalloc (blen);
4968 result = get_token_information (token, TokenUser,
4969 (LPVOID)buf, blen, &needed);
4970 if (result)
4972 memcpy (&user_token, buf, sizeof (user_token));
4973 if (!w32_cached_id (user_token.User.Sid, &euid, uname))
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
4984 strcpy (uname, "unknown");
4985 result = TRUE;
4988 ulength = strlen (uname);
4992 if (result)
4994 /* Determine a reasonable euid and gid values. */
4995 if (xstrcasecmp ("administrator", uname) == 0)
4997 euid = 500; /* well-known Administrator uid */
4998 egid = 513; /* well-known None gid */
5000 else
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)
5007 buf = xrealloc (buf, blen = needed);
5008 result = get_token_information (token, TokenPrimaryGroup,
5009 (LPVOID)buf, blen, &needed);
5011 if (result)
5013 memcpy (&group_token, buf, sizeof (group_token));
5014 if (!w32_cached_id (group_token.PrimaryGroup, &egid, gname))
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
5027 strcpy (gname, "None");
5028 result = TRUE;
5031 glength = strlen (gname);
5035 xfree (buf);
5037 if (!result)
5039 if (!is_windows_9x ())
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);
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))
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);
5065 else
5067 euid = 123;
5068 egid = 123;
5069 strcpy (uname, "administrator");
5070 ulength = strlen (uname);
5071 strcpy (gname, "None");
5072 glength = strlen (gname);
5074 if (token)
5075 CloseHandle (token);
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);
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... */
5096 DWORD tot_hi = memstex.ullTotalPhys >> 32;
5097 DWORD tot_md = (memstex.ullTotalPhys & 0x00000000ffffffff) >> 10;
5098 DWORD tot_lo = memstex.ullTotalPhys % 1024;
5100 totphys = tot_hi * 4194304.0 + tot_md + tot_lo / 1024.0;
5102 #endif /* __GNUC__ || _MSC_VER >= 1300 */
5103 else if (global_memory_status (&memst))
5104 totphys = memst.dwTotalPhys / 1024.0;
5106 if (h_proc
5107 && get_process_memory_info (h_proc, (PROCESS_MEMORY_COUNTERS *)&mem_ex,
5108 sizeof (mem_ex)))
5110 DWORD rss = mem_ex.WorkingSetSize / 1024;
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);
5122 else if (h_proc
5123 && get_process_memory_info (h_proc, &mem, sizeof (mem)))
5125 DWORD rss = mem_ex.WorkingSetSize / 1024;
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);
5134 else if (h_proc
5135 && get_process_working_set_size (h_proc, &minrss, &maxrss))
5137 DWORD rss = maxrss / 1024;
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);
5144 if (process_times (h_proc, &ctime, &etime, &stime, &utime, &ttime, &pcpu))
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);
5154 /* FIXME: Retrieve command line by walking the PEB of the process. */
5156 if (h_proc)
5157 CloseHandle (h_proc);
5158 UNGCPRO;
5159 return attrs;
5163 /* Wrappers for winsock functions to map between our file descriptors
5164 and winsock's handles; also set h_errno for convenience.
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). */
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);
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);
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
5212 HANDLE winsock_lib;
5213 static int winsock_inuse;
5215 BOOL
5216 term_winsock (void)
5218 if (winsock_lib != NULL && winsock_inuse == 0)
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)
5226 if (FreeLibrary (winsock_lib))
5227 winsock_lib = NULL;
5228 return TRUE;
5231 return FALSE;
5234 BOOL
5235 init_winsock (int load_now)
5237 WSADATA winsockData;
5239 if (winsock_lib != NULL)
5240 return TRUE;
5242 pfn_SetHandleInformation
5243 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
5244 "SetHandleInformation");
5246 winsock_lib = LoadLibrary ("Ws2_32.dll");
5248 if (winsock_lib != NULL)
5250 /* dynamically link to socket functions */
5252 #define LOAD_PROC(fn) \
5253 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
5254 goto fail;
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
5286 /* specify version 1.1 of winsock */
5287 if (pfn_WSAStartup (0x101, &winsockData) == 0)
5289 if (winsockData.wVersion != 0x101)
5290 goto fail;
5292 if (!load_now)
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. */
5300 pfn_WSACleanup ();
5301 FreeLibrary (winsock_lib);
5302 winsock_lib = NULL;
5304 winsock_inuse = 0;
5305 return TRUE;
5308 fail:
5309 FreeLibrary (winsock_lib);
5310 winsock_lib = NULL;
5313 return FALSE;
5317 int h_errno = 0;
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)
5325 if (winsock_lib == NULL)
5326 h_errno = EINVAL;
5327 else
5328 h_errno = pfn_WSAGetLastError ();
5330 switch (h_errno)
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;
5341 errno = h_errno;
5344 static void
5345 check_errno (void)
5347 if (h_errno == 0 && winsock_lib != NULL)
5348 pfn_WSASetLastError (0);
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"},
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 */
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
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"},
5424 {-1, NULL}
5427 char *
5428 sys_strerror (int error_no)
5430 int i;
5431 static char unknown_msg[40];
5433 if (error_no >= 0 && error_no < sys_nerr)
5434 return sys_errlist[error_no];
5436 for (i = 0; _wsa_errlist[i].errnum >= 0; i++)
5437 if (_wsa_errlist[i].errnum == error_no)
5438 return _wsa_errlist[i].msg;
5440 sprintf (unknown_msg, "Unidentified error: %d", error_no);
5441 return unknown_msg;
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. */
5448 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
5450 static int socket_to_fd (SOCKET s);
5453 sys_socket (int af, int type, int protocol)
5455 SOCKET s;
5457 if (winsock_lib == NULL)
5459 h_errno = ENETDOWN;
5460 return INVALID_SOCKET;
5463 check_errno ();
5465 /* call the real socket function */
5466 s = pfn_socket (af, type, protocol);
5468 if (s != INVALID_SOCKET)
5469 return socket_to_fd (s);
5471 set_errno ();
5472 return -1;
5475 /* Convert a SOCKET to a file descriptor. */
5476 static int
5477 socket_to_fd (SOCKET s)
5479 int fd;
5480 child_process * cp;
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. */
5488 /* allocate a file descriptor (with appropriate flags) */
5489 fd = _open ("NUL:", _O_RDWR);
5490 if (fd >= 0)
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. */
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)
5504 pfn_SetHandleInformation ((HANDLE) s, HANDLE_FLAG_INHERIT, 0);
5506 else
5508 HANDLE parent = GetCurrentProcess ();
5509 HANDLE new_s = INVALID_HANDLE_VALUE;
5511 if (DuplicateHandle (parent,
5512 (HANDLE) s,
5513 parent,
5514 &new_s,
5516 FALSE,
5517 DUPLICATE_SAME_ACCESS))
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)
5526 pfn_closesocket (s);
5527 s = (SOCKET) new_s;
5529 else
5531 CloseHandle (new_s);
5536 fd_info[fd].hnd = (HANDLE) s;
5538 /* set our own internal flags */
5539 fd_info[fd].flags = FILE_SOCKET | FILE_BINARY | FILE_READ | FILE_WRITE;
5541 cp = new_child ();
5542 if (cp)
5544 cp->fd = fd;
5545 cp->status = STATUS_READ_ACKNOWLEDGED;
5547 /* attach child_process to fd_info */
5548 if (fd_info[ fd ].cp != NULL)
5550 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd));
5551 emacs_abort ();
5554 fd_info[ fd ].cp = cp;
5556 /* success! */
5557 winsock_inuse++; /* count open sockets */
5558 return fd;
5561 /* clean up */
5562 _close (fd);
5564 pfn_closesocket (s);
5565 h_errno = EMFILE;
5566 return -1;
5570 sys_bind (int s, const struct sockaddr * addr, int namelen)
5572 if (winsock_lib == NULL)
5574 h_errno = ENOTSOCK;
5575 return SOCKET_ERROR;
5578 check_errno ();
5579 if (fd_info[s].flags & FILE_SOCKET)
5581 int rc = pfn_bind (SOCK_HANDLE (s), addr, namelen);
5582 if (rc == SOCKET_ERROR)
5583 set_errno ();
5584 return rc;
5586 h_errno = ENOTSOCK;
5587 return SOCKET_ERROR;
5591 sys_connect (int s, const struct sockaddr * name, int namelen)
5593 if (winsock_lib == NULL)
5595 h_errno = ENOTSOCK;
5596 return SOCKET_ERROR;
5599 check_errno ();
5600 if (fd_info[s].flags & FILE_SOCKET)
5602 int rc = pfn_connect (SOCK_HANDLE (s), name, namelen);
5603 if (rc == SOCKET_ERROR)
5604 set_errno ();
5605 return rc;
5607 h_errno = ENOTSOCK;
5608 return SOCKET_ERROR;
5611 u_short
5612 sys_htons (u_short hostshort)
5614 return (winsock_lib != NULL) ?
5615 pfn_htons (hostshort) : hostshort;
5618 u_short
5619 sys_ntohs (u_short netshort)
5621 return (winsock_lib != NULL) ?
5622 pfn_ntohs (netshort) : netshort;
5625 unsigned long
5626 sys_inet_addr (const char * cp)
5628 return (winsock_lib != NULL) ?
5629 pfn_inet_addr (cp) : INADDR_NONE;
5633 sys_gethostname (char * name, int namelen)
5635 if (winsock_lib != NULL)
5636 return pfn_gethostname (name, namelen);
5638 if (namelen > MAX_COMPUTERNAME_LENGTH)
5639 return !GetComputerName (name, (DWORD *)&namelen);
5641 h_errno = EFAULT;
5642 return SOCKET_ERROR;
5645 struct hostent *
5646 sys_gethostbyname (const char * name)
5648 struct hostent * host;
5650 if (winsock_lib == NULL)
5652 h_errno = ENETDOWN;
5653 return NULL;
5656 check_errno ();
5657 host = pfn_gethostbyname (name);
5658 if (!host)
5659 set_errno ();
5660 return host;
5663 struct servent *
5664 sys_getservbyname (const char * name, const char * proto)
5666 struct servent * serv;
5668 if (winsock_lib == NULL)
5670 h_errno = ENETDOWN;
5671 return NULL;
5674 check_errno ();
5675 serv = pfn_getservbyname (name, proto);
5676 if (!serv)
5677 set_errno ();
5678 return serv;
5682 sys_getpeername (int s, struct sockaddr *addr, int * namelen)
5684 if (winsock_lib == NULL)
5686 h_errno = ENETDOWN;
5687 return SOCKET_ERROR;
5690 check_errno ();
5691 if (fd_info[s].flags & FILE_SOCKET)
5693 int rc = pfn_getpeername (SOCK_HANDLE (s), addr, namelen);
5694 if (rc == SOCKET_ERROR)
5695 set_errno ();
5696 return rc;
5698 h_errno = ENOTSOCK;
5699 return SOCKET_ERROR;
5703 sys_shutdown (int s, int how)
5705 if (winsock_lib == NULL)
5707 h_errno = ENETDOWN;
5708 return SOCKET_ERROR;
5711 check_errno ();
5712 if (fd_info[s].flags & FILE_SOCKET)
5714 int rc = pfn_shutdown (SOCK_HANDLE (s), how);
5715 if (rc == SOCKET_ERROR)
5716 set_errno ();
5717 return rc;
5719 h_errno = ENOTSOCK;
5720 return SOCKET_ERROR;
5724 sys_setsockopt (int s, int level, int optname, const void * optval, int optlen)
5726 if (winsock_lib == NULL)
5728 h_errno = ENETDOWN;
5729 return SOCKET_ERROR;
5732 check_errno ();
5733 if (fd_info[s].flags & FILE_SOCKET)
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;
5741 h_errno = ENOTSOCK;
5742 return SOCKET_ERROR;
5746 sys_listen (int s, int backlog)
5748 if (winsock_lib == NULL)
5750 h_errno = ENETDOWN;
5751 return SOCKET_ERROR;
5754 check_errno ();
5755 if (fd_info[s].flags & FILE_SOCKET)
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;
5764 h_errno = ENOTSOCK;
5765 return SOCKET_ERROR;
5769 sys_getsockname (int s, struct sockaddr * name, int * namelen)
5771 if (winsock_lib == NULL)
5773 h_errno = ENETDOWN;
5774 return SOCKET_ERROR;
5777 check_errno ();
5778 if (fd_info[s].flags & FILE_SOCKET)
5780 int rc = pfn_getsockname (SOCK_HANDLE (s), name, namelen);
5781 if (rc == SOCKET_ERROR)
5782 set_errno ();
5783 return rc;
5785 h_errno = ENOTSOCK;
5786 return SOCKET_ERROR;
5790 sys_accept (int s, struct sockaddr * addr, int * addrlen)
5792 if (winsock_lib == NULL)
5794 h_errno = ENETDOWN;
5795 return -1;
5798 check_errno ();
5799 if (fd_info[s].flags & FILE_LISTEN)
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);
5808 fd_info[s].cp->status = STATUS_READ_ACKNOWLEDGED;
5809 ResetEvent (fd_info[s].cp->char_avail);
5810 return fd;
5812 h_errno = ENOTSOCK;
5813 return -1;
5817 sys_recvfrom (int s, char * buf, int len, int flags,
5818 struct sockaddr * from, int * fromlen)
5820 if (winsock_lib == NULL)
5822 h_errno = ENETDOWN;
5823 return SOCKET_ERROR;
5826 check_errno ();
5827 if (fd_info[s].flags & FILE_SOCKET)
5829 int rc = pfn_recvfrom (SOCK_HANDLE (s), buf, len, flags, from, fromlen);
5830 if (rc == SOCKET_ERROR)
5831 set_errno ();
5832 return rc;
5834 h_errno = ENOTSOCK;
5835 return SOCKET_ERROR;
5839 sys_sendto (int s, const char * buf, int len, int flags,
5840 const struct sockaddr * to, int tolen)
5842 if (winsock_lib == NULL)
5844 h_errno = ENETDOWN;
5845 return SOCKET_ERROR;
5848 check_errno ();
5849 if (fd_info[s].flags & FILE_SOCKET)
5851 int rc = pfn_sendto (SOCK_HANDLE (s), buf, len, flags, to, tolen);
5852 if (rc == SOCKET_ERROR)
5853 set_errno ();
5854 return rc;
5856 h_errno = ENOTSOCK;
5857 return SOCKET_ERROR;
5860 /* Windows does not have an fcntl function. Provide an implementation
5861 solely for making sockets non-blocking. */
5863 fcntl (int s, int cmd, int options)
5865 if (winsock_lib == NULL)
5867 h_errno = ENETDOWN;
5868 return -1;
5871 check_errno ();
5872 if (fd_info[s].flags & FILE_SOCKET)
5874 if (cmd == F_SETFL && options == O_NONBLOCK)
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;
5884 else
5886 h_errno = EINVAL;
5887 return SOCKET_ERROR;
5890 h_errno = ENOTSOCK;
5891 return SOCKET_ERROR;
5895 /* Shadow main io functions: we need to handle pipes and sockets more
5896 intelligently, and implement non-blocking mode as well. */
5899 sys_close (int fd)
5901 int rc;
5903 if (fd < 0)
5905 errno = EBADF;
5906 return -1;
5909 if (fd < MAXDESC && fd_info[fd].cp)
5911 child_process * cp = fd_info[fd].cp;
5913 fd_info[fd].cp = NULL;
5915 if (CHILD_ACTIVE (cp))
5917 /* if last descriptor to active child_process then cleanup */
5918 int i;
5919 for (i = 0; i < MAXDESC; i++)
5921 if (i == fd)
5922 continue;
5923 if (fd_info[i].cp == cp)
5924 break;
5926 if (i == MAXDESC)
5928 if (fd_info[fd].flags & FILE_SOCKET)
5930 if (winsock_lib == NULL) emacs_abort ();
5932 pfn_shutdown (SOCK_HANDLE (fd), 2);
5933 rc = pfn_closesocket (SOCK_HANDLE (fd));
5935 winsock_inuse--; /* count open sockets */
5937 delete_child (cp);
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);
5948 if (rc == 0 && fd < MAXDESC)
5949 fd_info[fd].flags = 0;
5951 return rc;
5955 sys_dup (int fd)
5957 int new_fd;
5959 new_fd = _dup (fd);
5960 if (new_fd >= 0 && new_fd < MAXDESC)
5962 /* duplicate our internal info as well */
5963 fd_info[new_fd] = fd_info[fd];
5965 return new_fd;
5969 sys_dup2 (int src, int dst)
5971 int rc;
5973 if (dst < 0 || dst >= MAXDESC)
5975 errno = EBADF;
5976 return -1;
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);
5983 rc = _dup2 (src, dst);
5984 if (rc == 0)
5986 /* duplicate our internal info as well */
5987 fd_info[dst] = fd_info[src];
5989 return rc;
5992 /* Unix pipe() has only one arg */
5994 sys_pipe (int * phandles)
5996 int rc;
5997 unsigned flags;
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);
6005 if (rc == 0)
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)
6011 _close (phandles[0]);
6012 _close (phandles[1]);
6013 rc = -1;
6015 else
6017 flags = FILE_PIPE | FILE_READ | FILE_BINARY;
6018 fd_info[phandles[0]].flags = flags;
6020 flags = FILE_PIPE | FILE_WRITE | FILE_BINARY;
6021 fd_info[phandles[1]].flags = flags;
6025 return rc;
6028 /* Function to do blocking read of one byte, needed to implement
6029 select. It is only allowed on sockets and pipes. */
6031 _sys_read_ahead (int fd)
6033 child_process * cp;
6034 int rc;
6036 if (fd < 0 || fd >= MAXDESC)
6037 return STATUS_READ_ERROR;
6039 cp = fd_info[fd].cp;
6041 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
6042 return STATUS_READ_ERROR;
6044 if ((fd_info[fd].flags & (FILE_PIPE | FILE_SERIAL | FILE_SOCKET)) == 0
6045 || (fd_info[fd].flags & FILE_READ) == 0)
6047 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd));
6048 emacs_abort ();
6051 cp->status = STATUS_READ_IN_PROGRESS;
6053 if (fd_info[fd].flags & FILE_PIPE)
6055 rc = _read (fd, &cp->chr, sizeof (char));
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)
6066 int wait = w32_pipe_read_delay;
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);
6077 else if (fd_info[fd].flags & FILE_SERIAL)
6079 HANDLE hnd = fd_info[fd].hnd;
6080 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
6081 COMMTIMEOUTS ct;
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;
6092 if (!ReadFile (hnd, &cp->chr, sizeof (char), (DWORD*) &rc, ovl))
6094 if (GetLastError () != ERROR_IO_PENDING)
6095 return STATUS_READ_ERROR;
6096 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
6097 return STATUS_READ_ERROR;
6100 else if (fd_info[fd].flags & FILE_SOCKET)
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);
6107 rc = pfn_recv (SOCK_HANDLE (fd), &cp->chr, sizeof (char), 0);
6109 if (fd_info[fd].flags & FILE_NDELAY)
6111 nblock = 1;
6112 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
6116 if (rc == sizeof (char))
6117 cp->status = STATUS_READ_SUCCEEDED;
6118 else
6119 cp->status = STATUS_READ_FAILED;
6121 return cp->status;
6125 _sys_wait_accept (int fd)
6127 HANDLE hEv;
6128 child_process * cp;
6129 int rc;
6131 if (fd < 0 || fd >= MAXDESC)
6132 return STATUS_READ_ERROR;
6134 cp = fd_info[fd].cp;
6136 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
6137 return STATUS_READ_ERROR;
6139 cp->status = STATUS_READ_FAILED;
6141 hEv = pfn_WSACreateEvent ();
6142 rc = pfn_WSAEventSelect (SOCK_HANDLE (fd), hEv, FD_ACCEPT);
6143 if (rc != SOCKET_ERROR)
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;
6150 pfn_WSACloseEvent (hEv);
6152 return cp->status;
6156 sys_read (int fd, char * buffer, unsigned int count)
6158 int nchars;
6159 int to_read;
6160 DWORD waiting;
6161 char * orig_buffer = buffer;
6163 if (fd < 0)
6165 errno = EBADF;
6166 return -1;
6169 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
6171 child_process *cp = fd_info[fd].cp;
6173 if ((fd_info[fd].flags & FILE_READ) == 0)
6175 errno = EBADF;
6176 return -1;
6179 nchars = 0;
6181 /* re-read CR carried over from last read */
6182 if (fd_info[fd].flags & FILE_LAST_CR)
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;
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)
6198 int current_status = cp->status;
6200 switch (current_status)
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;
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;
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);
6223 case STATUS_READ_ACKNOWLEDGED:
6224 break;
6226 default:
6227 DebPrint (("sys_read: bad status %d\n", current_status));
6228 errno = EBADF;
6229 return -1;
6232 if (fd_info[fd].flags & FILE_PIPE)
6234 PeekNamedPipe ((HANDLE) _get_osfhandle (fd), NULL, 0, NULL, &waiting, NULL);
6235 to_read = min (waiting, (DWORD) count);
6237 if (to_read > 0)
6238 nchars += _read (fd, buffer, to_read);
6240 else if (fd_info[fd].flags & FILE_SERIAL)
6242 HANDLE hnd = fd_info[fd].hnd;
6243 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
6244 int rc = 0;
6245 COMMTIMEOUTS ct;
6247 if (count > 0)
6249 /* Configure timeouts for non-blocking read. */
6250 if (!GetCommTimeouts (hnd, &ct))
6252 errno = EIO;
6253 return -1;
6255 ct.ReadIntervalTimeout = MAXDWORD;
6256 ct.ReadTotalTimeoutMultiplier = 0;
6257 ct.ReadTotalTimeoutConstant = 0;
6258 if (!SetCommTimeouts (hnd, &ct))
6260 errno = EIO;
6261 return -1;
6264 if (!ResetEvent (ovl->hEvent))
6266 errno = EIO;
6267 return -1;
6269 if (!ReadFile (hnd, buffer, count, (DWORD*) &rc, ovl))
6271 if (GetLastError () != ERROR_IO_PENDING)
6273 errno = EIO;
6274 return -1;
6276 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
6278 errno = EIO;
6279 return -1;
6282 nchars += rc;
6285 else /* FILE_SOCKET */
6287 if (winsock_lib == NULL) emacs_abort ();
6289 /* do the equivalent of a non-blocking read */
6290 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONREAD, &waiting);
6291 if (waiting == 0 && nchars == 0)
6293 h_errno = errno = EWOULDBLOCK;
6294 return -1;
6297 if (waiting)
6299 /* always use binary mode for sockets */
6300 int res = pfn_recv (SOCK_HANDLE (fd), buffer, count, 0);
6301 if (res == SOCKET_ERROR)
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;
6308 nchars += res;
6312 else
6314 int nread = _read (fd, buffer, count);
6315 if (nread >= 0)
6316 nchars += nread;
6317 else if (nchars == 0)
6318 nchars = nread;
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)
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)
6333 fd_info[fd].flags |= FILE_LAST_CR;
6334 nchars--;
6338 else
6339 nchars = _read (fd, buffer, count);
6341 return nchars;
6344 /* From w32xfns.c */
6345 extern HANDLE interrupt_handle;
6347 /* For now, don't bother with a non-blocking mode */
6349 sys_write (int fd, const void * buffer, unsigned int count)
6351 int nchars;
6353 if (fd < 0)
6355 errno = EBADF;
6356 return -1;
6359 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
6361 if ((fd_info[fd].flags & FILE_WRITE) == 0)
6363 errno = EBADF;
6364 return -1;
6367 /* Perform text mode translation if required. */
6368 if ((fd_info[fd].flags & FILE_BINARY) == 0)
6370 char * tmpbuf = alloca (count * 2);
6371 unsigned char * src = (void *)buffer;
6372 unsigned char * dst = tmpbuf;
6373 int nbytes = count;
6375 while (1)
6377 unsigned char *next;
6378 /* copy next line or remaining bytes */
6379 next = _memccpy (dst, src, '\n', nbytes);
6380 if (next)
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++;
6392 else
6393 /* copied remaining partial line -> now finished */
6394 break;
6396 buffer = tmpbuf;
6400 if (fd < MAXDESC && fd_info[fd].flags & FILE_SERIAL)
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;
6407 if (!WriteFile (hnd, buffer, count, (DWORD*) &nchars, ovl))
6409 if (GetLastError () != ERROR_IO_PENDING)
6411 errno = EIO;
6412 return -1;
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;
6427 if (active == WAIT_OBJECT_0 + 1
6428 && !GetOverlappedResult (hnd, ovl, (DWORD*) &nchars, TRUE))
6430 errno = EIO;
6431 return -1;
6435 else if (fd < MAXDESC && fd_info[fd].flags & FILE_SOCKET)
6437 unsigned long nblock = 0;
6438 if (winsock_lib == NULL) emacs_abort ();
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);
6445 nchars = pfn_send (SOCK_HANDLE (fd), buffer, count, 0);
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)
6451 nblock = 1;
6452 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
6455 if (nchars == SOCKET_ERROR)
6457 DebPrint (("sys_write.send failed with error %d on socket %ld\n",
6458 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
6459 set_errno ();
6462 else
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;
6473 nchars = 0;
6474 while (count > 0)
6476 unsigned this_chunk = count < chunk ? count : chunk;
6477 int n = _write (fd, p, this_chunk);
6479 nchars += n;
6480 if (n < 0)
6482 nchars = n;
6483 break;
6485 else if (n < this_chunk)
6486 break;
6487 count -= n;
6488 p += n;
6492 return nchars;
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)
6504 tzset ();
6505 return localtime (t);
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.
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)
6522 HMODULE library_dll = NULL;
6524 CHECK_SYMBOL (library_id);
6526 if (CONSP (Vdynamic_library_alist)
6527 && NILP (Fassq (library_id, Vlibrary_cache)))
6529 Lisp_Object found = Qnil;
6530 Lisp_Object dlls = Fassq (library_id, Vdynamic_library_alist);
6532 if (CONSP (dlls))
6533 for (dlls = XCDR (dlls); CONSP (dlls); dlls = XCDR (dlls))
6535 CHECK_STRING_CAR (dlls);
6536 if ((library_dll = LoadLibrary (SDATA (XCAR (dlls)))))
6538 char name[MAX_PATH];
6539 DWORD len;
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;
6551 Fput (library_id, QCloaded_from, found);
6554 return library_dll;
6558 void
6559 check_windows_init_file (void)
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. */
6565 if (!noninteractive && !inhibit_window_system
6566 /* Vload_path is not yet initialized when we are loading
6567 loadup.el. */
6568 && NILP (Vpurify_flag))
6570 Lisp_Object init_file;
6571 int fd;
6573 init_file = build_string ("term/w32-win");
6574 fd = openp (Vload_path, init_file, Fget_load_suffixes (), NULL, Qnil);
6575 if (fd < 0)
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));
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 ();
6601 else
6603 _close (fd);
6608 void
6609 term_ntproc (int ignored)
6611 (void)ignored;
6613 term_timers ();
6615 /* shutdown the socket interface if necessary */
6616 term_winsock ();
6618 term_w32select ();
6621 void
6622 init_ntproc (int dumping)
6624 sigset_t initial_mask = 0;
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).
6631 Conveniently, init_environment is called before us, so
6632 PRELOAD_WINSOCK can be set in the registry. */
6634 /* Always initialize this correctly. */
6635 winsock_lib = NULL;
6637 if (getenv ("PRELOAD_WINSOCK") != NULL)
6638 init_winsock (TRUE);
6640 /* Initial preparation for subprocess support: replace our standard
6641 handles with non-inheritable versions. */
6643 HANDLE parent;
6644 HANDLE stdin_save = INVALID_HANDLE_VALUE;
6645 HANDLE stdout_save = INVALID_HANDLE_VALUE;
6646 HANDLE stderr_save = INVALID_HANDLE_VALUE;
6648 parent = GetCurrentProcess ();
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,
6657 FALSE,
6658 DUPLICATE_SAME_ACCESS);
6660 DuplicateHandle (parent,
6661 GetStdHandle (STD_OUTPUT_HANDLE),
6662 parent,
6663 &stdout_save,
6665 FALSE,
6666 DUPLICATE_SAME_ACCESS);
6668 DuplicateHandle (parent,
6669 GetStdHandle (STD_ERROR_HANDLE),
6670 parent,
6671 &stderr_save,
6673 FALSE,
6674 DUPLICATE_SAME_ACCESS);
6676 fclose (stdin);
6677 fclose (stdout);
6678 fclose (stderr);
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");
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");
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");
6699 /* unfortunately, atexit depends on implementation of malloc */
6700 /* atexit (term_ntproc); */
6701 if (!dumping)
6703 /* Make sure we start with all signals unblocked. */
6704 sigprocmask (SIG_SETMASK, &initial_mask, NULL);
6705 signal (SIGABRT, term_ntproc);
6707 init_timers ();
6709 /* determine which drives are fixed, for GetCachedVolumeInformation */
6711 /* GetDriveType must have trailing backslash. */
6712 char drive[] = "A:\\";
6714 /* Loop over all possible drive letters */
6715 while (*drive <= 'Z')
6717 /* Record if this drive letter refers to a fixed drive. */
6718 fixed_drives[DRIVE_INDEX (*drive)] =
6719 (GetDriveType (drive) == DRIVE_FIXED);
6721 (*drive)++;
6724 /* Reset the volume info cache. */
6725 volume_cache = NULL;
6730 shutdown_handler ensures that buffers' autosave files are
6731 up to date when the user logs off, or the system shuts down.
6733 static BOOL WINAPI
6734 shutdown_handler (DWORD type)
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. */
6741 /* Shut down cleanly, making sure autosave files are up to date. */
6742 shut_down_emacs (0, Qnil);
6745 /* Allow other handlers to handle this signal. */
6746 return FALSE;
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).
6754 void
6755 globals_of_w32 (void)
6757 HMODULE kernel32 = GetModuleHandle ("kernel32.dll");
6759 get_process_times_fn = (GetProcessTimes_Proc)
6760 GetProcAddress (kernel32, "GetProcessTimes");
6762 DEFSYM (QCloaded_from, ":loaded-from");
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);
6798 /* "None" is the default group name on standalone workstations. */
6799 strcpy (dflt_group_name, "None");
6802 /* For make-serial-process */
6804 serial_open (char *port)
6806 HANDLE hnd;
6807 child_process *cp;
6808 int fd = -1;
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);
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)
6828 error ("fd_info[fd = %d] is already in use", fd);
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");
6838 return fd;
6841 /* For serial-process-configure */
6842 void
6843 serial_configure (struct Lisp_Process *p, Lisp_Object contact)
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". */
6852 if ((fd_info[ p->outfd ].flags & FILE_SERIAL) == 0)
6853 error ("Not a serial process");
6854 hnd = fd_info[ p->outfd ].hnd;
6856 childp2 = Fcopy_sequence (p->childp);
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;
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);
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);
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))
6916 summary[1] = 'N';
6918 else if (EQ (tem, Qeven))
6920 summary[1] = 'E';
6921 dcb.fParity = TRUE;
6922 dcb.Parity = EVENPARITY;
6923 dcb.fErrorChar = TRUE;
6925 else if (EQ (tem, Qodd))
6927 summary[1] = 'O';
6928 dcb.fParity = TRUE;
6929 dcb.Parity = ODDPARITY;
6930 dcb.fErrorChar = TRUE;
6932 childp2 = Fplist_put (childp2, QCparity, tem);
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);
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))
6970 /* Already configured. */
6972 else if (EQ (tem, Qhw))
6974 dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
6975 dcb.fOutxCtsFlow = TRUE;
6977 else if (EQ (tem, Qsw))
6979 dcb.fOutX = TRUE;
6980 dcb.fInX = TRUE;
6982 childp2 = Fplist_put (childp2, QCflowcontrol, tem);
6984 /* Activate configuration. */
6985 if (!SetCommState (hnd, &dcb))
6986 error ("SetCommState() failed");
6988 childp2 = Fplist_put (childp2, QCsummary, build_string (summary));
6989 pset_childp (p, childp2);
6992 #ifdef HAVE_GNUTLS
6994 ssize_t
6995 emacs_gnutls_pull (gnutls_transport_ptr_t p, void* buf, size_t sz)
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;
7003 for (;;)
7005 n = sys_read (fd, (char*)buf, sz);
7007 if (n >= 0)
7008 return n;
7010 err = errno;
7012 if (err == EWOULDBLOCK)
7014 /* Set a small timeout. */
7015 timeout = make_emacs_time (1, 0);
7016 FD_ZERO (&fdset);
7017 FD_SET ((int)fd, &fdset);
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);
7023 if (sc > 0)
7024 continue; /* Try again. */
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. */
7034 emacs_gnutls_transport_set_errno (process->gnutls_state, err);
7036 return -1;
7040 ssize_t
7041 emacs_gnutls_push (gnutls_transport_ptr_t p, const void* buf, size_t sz)
7043 struct Lisp_Process *process = (struct Lisp_Process *)p;
7044 int fd = process->outfd;
7045 ssize_t n = sys_write (fd, buf, sz);
7047 /* 0 or more bytes written means everything went fine. */
7048 if (n >= 0)
7049 return n;
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);
7056 return -1;
7058 #endif /* HAVE_GNUTLS */
7060 /* end of w32.c */