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