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