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