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