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