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