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