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