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