Daniel Engeler <engeler at gmail.com>
[bpt/emacs.git] / src / w32.c
CommitLineData
e9e23e23 1/* Utility and Unix shadow routines for GNU Emacs on the Microsoft W32 API.
0b5538bd 2 Copyright (C) 1994, 1995, 2000, 2001, 2002, 2003, 2004,
8cabe764 3 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
95ed0025 4
3b7ad313
EN
5This file is part of GNU Emacs.
6
9ec0b715 7GNU Emacs is free software: you can redistribute it and/or modify
3b7ad313 8it under the terms of the GNU General Public License as published by
9ec0b715
GM
9the Free Software Foundation, either version 3 of the License, or
10(at your option) any later version.
3b7ad313
EN
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
9ec0b715 18along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
95ed0025 19
9ec0b715 20/*
95ed0025
RS
21 Geoff Voelker (voelker@cs.washington.edu) 7-29-94
22*/
76b3903d 23#include <stddef.h> /* for offsetof */
95ed0025
RS
24#include <stdlib.h>
25#include <stdio.h>
26#include <io.h>
480b0c5b 27#include <errno.h>
95ed0025
RS
28#include <fcntl.h>
29#include <ctype.h>
480b0c5b 30#include <signal.h>
b3308d2e 31#include <sys/file.h>
480b0c5b 32#include <sys/time.h>
16bb7578 33#include <sys/utime.h>
22189f79 34#include <mbstring.h> /* for _mbspbrk */
480b0c5b
GV
35
36/* must include CRT headers *before* config.h */
4838e624
PJ
37
38#ifdef HAVE_CONFIG_H
39#include <config.h>
40#endif
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
95ed0025 65#include "lisp.h"
95ed0025
RS
66
67#include <pwd.h>
3d19b645 68#include <grp.h>
95ed0025 69
971bce75
AI
70#ifdef __GNUC__
71#define _ANONYMOUS_UNION
72#define _ANONYMOUS_STRUCT
73#endif
480b0c5b 74#include <windows.h>
634d3003 75#include <lmcons.h>
2d5324c5 76#include <shlobj.h>
00b3b7b3 77
480b0c5b
GV
78#ifdef HAVE_SOCKETS /* TCP connection support, if kernel can do it */
79#include <sys/socket.h>
80#undef socket
81#undef bind
82#undef connect
83#undef htons
84#undef ntohs
85#undef inet_addr
86#undef gethostname
87#undef gethostbyname
88#undef getservbyname
ecd270eb 89#undef getpeername
380961a6 90#undef shutdown
962955c5
JR
91#undef setsockopt
92#undef listen
93#undef getsockname
94#undef accept
95#undef recvfrom
96#undef sendto
480b0c5b 97#endif
00b3b7b3 98
489f9371 99#include "w32.h"
480b0c5b 100#include "ndir.h"
489f9371 101#include "w32heap.h"
253574a6 102#include "systime.h"
f481eb31 103#include "dispextern.h" /* for xstrcasecmp */
253574a6 104
2d5324c5
JR
105typedef HRESULT (WINAPI * ShGetFolderPath_fn)
106 (IN HWND, IN int, IN HANDLE, IN DWORD, OUT char *);
107
9785d95b 108void globals_of_w32 ();
8aaaec6b 109static DWORD get_rid (PSID);
9785d95b 110
76b3903d
GV
111extern Lisp_Object Vw32_downcase_file_names;
112extern Lisp_Object Vw32_generate_fake_inodes;
113extern Lisp_Object Vw32_get_true_file_attributes;
ac0af113
JR
114/* Defined in process.c for its own purpose. */
115extern Lisp_Object Qlocal;
116
e0c181dd 117extern int w32_num_mouse_buttons;
76b3903d 118
18e070ac 119\f
9d95a291
EZ
120/* Initialization states.
121
122 WARNING: If you add any more such variables for additional APIs,
123 you MUST add initialization for them to globals_of_w32
124 below. This is because these variables might get set
125 to non-NULL values during dumping, but the dumped Emacs
126 cannot reuse those values, because it could be run on a
127 different version of the OS, where API addresses are
128 different. */
9785d95b
BK
129static BOOL g_b_init_is_windows_9x;
130static BOOL g_b_init_open_process_token;
131static BOOL g_b_init_get_token_information;
132static BOOL g_b_init_lookup_account_sid;
133static BOOL g_b_init_get_sid_identifier_authority;
c617afce
EZ
134static BOOL g_b_init_get_sid_sub_authority;
135static BOOL g_b_init_get_sid_sub_authority_count;
8aaaec6b
EZ
136static BOOL g_b_init_get_file_security;
137static BOOL g_b_init_get_security_descriptor_owner;
138static BOOL g_b_init_get_security_descriptor_group;
139static BOOL g_b_init_is_valid_sid;
9785d95b 140
f60ae425
BK
141/*
142 BEGIN: Wrapper functions around OpenProcessToken
143 and other functions in advapi32.dll that are only
144 supported in Windows NT / 2k / XP
145*/
146 /* ** Function pointer typedefs ** */
147typedef BOOL (WINAPI * OpenProcessToken_Proc) (
148 HANDLE ProcessHandle,
149 DWORD DesiredAccess,
150 PHANDLE TokenHandle);
151typedef BOOL (WINAPI * GetTokenInformation_Proc) (
152 HANDLE TokenHandle,
153 TOKEN_INFORMATION_CLASS TokenInformationClass,
154 LPVOID TokenInformation,
155 DWORD TokenInformationLength,
156 PDWORD ReturnLength);
74258518
JR
157typedef BOOL (WINAPI * GetProcessTimes_Proc) (
158 HANDLE process_handle,
159 LPFILETIME creation_time,
160 LPFILETIME exit_time,
161 LPFILETIME kernel_time,
162 LPFILETIME user_time);
163
164GetProcessTimes_Proc get_process_times_fn = NULL;
165
f60ae425
BK
166#ifdef _UNICODE
167const char * const LookupAccountSid_Name = "LookupAccountSidW";
8aaaec6b 168const char * const GetFileSecurity_Name = "GetFileSecurityW";
f60ae425
BK
169#else
170const char * const LookupAccountSid_Name = "LookupAccountSidA";
8aaaec6b 171const char * const GetFileSecurity_Name = "GetFileSecurityA";
f60ae425
BK
172#endif
173typedef BOOL (WINAPI * LookupAccountSid_Proc) (
174 LPCTSTR lpSystemName,
175 PSID Sid,
176 LPTSTR Name,
177 LPDWORD cbName,
178 LPTSTR DomainName,
179 LPDWORD cbDomainName,
180 PSID_NAME_USE peUse);
181typedef PSID_IDENTIFIER_AUTHORITY (WINAPI * GetSidIdentifierAuthority_Proc) (
182 PSID pSid);
c617afce
EZ
183typedef PDWORD (WINAPI * GetSidSubAuthority_Proc) (
184 PSID pSid,
185 DWORD n);
186typedef PUCHAR (WINAPI * GetSidSubAuthorityCount_Proc) (
187 PSID pSid);
8aaaec6b
EZ
188typedef BOOL (WINAPI * GetFileSecurity_Proc) (
189 LPCTSTR lpFileName,
190 SECURITY_INFORMATION RequestedInformation,
191 PSECURITY_DESCRIPTOR pSecurityDescriptor,
192 DWORD nLength,
193 LPDWORD lpnLengthNeeded);
194typedef BOOL (WINAPI * GetSecurityDescriptorOwner_Proc) (
195 PSECURITY_DESCRIPTOR pSecurityDescriptor,
196 PSID *pOwner,
197 LPBOOL lpbOwnerDefaulted);
198typedef BOOL (WINAPI * GetSecurityDescriptorGroup_Proc) (
199 PSECURITY_DESCRIPTOR pSecurityDescriptor,
200 PSID *pGroup,
201 LPBOOL lpbGroupDefaulted);
202typedef BOOL (WINAPI * IsValidSid_Proc) (
203 PSID sid);
f60ae425
BK
204
205 /* ** A utility function ** */
9bfb11f9
KS
206static BOOL
207is_windows_9x ()
f60ae425 208{
9785d95b 209 static BOOL s_b_ret=0;
f60ae425 210 OSVERSIONINFO os_ver;
9785d95b 211 if (g_b_init_is_windows_9x == 0)
f60ae425 212 {
9785d95b
BK
213 g_b_init_is_windows_9x = 1;
214 ZeroMemory(&os_ver, sizeof(OSVERSIONINFO));
215 os_ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
216 if (GetVersionEx (&os_ver))
217 {
218 s_b_ret = (os_ver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
219 }
f60ae425 220 }
9785d95b 221 return s_b_ret;
f60ae425
BK
222}
223
74258518
JR
224/* Get total user and system times for get-internal-run-time.
225 Returns a list of three integers if the times are provided by the OS
226 (NT derivatives), otherwise it returns the result of current-time. */
227Lisp_Object
228w32_get_internal_run_time ()
229{
230 if (get_process_times_fn)
231 {
232 FILETIME create, exit, kernel, user;
233 HANDLE proc = GetCurrentProcess();
234 if ((*get_process_times_fn) (proc, &create, &exit, &kernel, &user))
235 {
236 LARGE_INTEGER user_int, kernel_int, total;
237 int microseconds;
238 user_int.LowPart = user.dwLowDateTime;
239 user_int.HighPart = user.dwHighDateTime;
240 kernel_int.LowPart = kernel.dwLowDateTime;
241 kernel_int.HighPart = kernel.dwHighDateTime;
242 total.QuadPart = user_int.QuadPart + kernel_int.QuadPart;
243 /* FILETIME is 100 nanosecond increments, Emacs only wants
244 microsecond resolution. */
245 total.QuadPart /= 10;
246 microseconds = total.QuadPart % 1000000;
247 total.QuadPart /= 1000000;
248
249 /* Sanity check to make sure we can represent the result. */
250 if (total.HighPart == 0)
251 {
252 int secs = total.LowPart;
253
254 return list3 (make_number ((secs >> 16) & 0xffff),
255 make_number (secs & 0xffff),
256 make_number (microseconds));
257 }
258 }
259 }
260
261 return Fcurrent_time ();
262}
263
f60ae425
BK
264 /* ** The wrapper functions ** */
265
266BOOL WINAPI open_process_token (
267 HANDLE ProcessHandle,
268 DWORD DesiredAccess,
269 PHANDLE TokenHandle)
270{
9785d95b 271 static OpenProcessToken_Proc s_pfn_Open_Process_Token = NULL;
f60ae425
BK
272 HMODULE hm_advapi32 = NULL;
273 if (is_windows_9x () == TRUE)
274 {
275 return FALSE;
276 }
9785d95b
BK
277 if (g_b_init_open_process_token == 0)
278 {
279 g_b_init_open_process_token = 1;
280 hm_advapi32 = LoadLibrary ("Advapi32.dll");
281 s_pfn_Open_Process_Token =
282 (OpenProcessToken_Proc) GetProcAddress (hm_advapi32, "OpenProcessToken");
283 }
284 if (s_pfn_Open_Process_Token == NULL)
f60ae425
BK
285 {
286 return FALSE;
287 }
288 return (
9785d95b 289 s_pfn_Open_Process_Token (
f60ae425
BK
290 ProcessHandle,
291 DesiredAccess,
292 TokenHandle)
293 );
294}
295
296BOOL WINAPI get_token_information (
297 HANDLE TokenHandle,
298 TOKEN_INFORMATION_CLASS TokenInformationClass,
299 LPVOID TokenInformation,
300 DWORD TokenInformationLength,
301 PDWORD ReturnLength)
302{
9785d95b 303 static GetTokenInformation_Proc s_pfn_Get_Token_Information = NULL;
f60ae425
BK
304 HMODULE hm_advapi32 = NULL;
305 if (is_windows_9x () == TRUE)
306 {
307 return FALSE;
308 }
9785d95b
BK
309 if (g_b_init_get_token_information == 0)
310 {
311 g_b_init_get_token_information = 1;
312 hm_advapi32 = LoadLibrary ("Advapi32.dll");
313 s_pfn_Get_Token_Information =
314 (GetTokenInformation_Proc) GetProcAddress (hm_advapi32, "GetTokenInformation");
315 }
316 if (s_pfn_Get_Token_Information == NULL)
f60ae425
BK
317 {
318 return FALSE;
319 }
320 return (
9785d95b 321 s_pfn_Get_Token_Information (
f60ae425
BK
322 TokenHandle,
323 TokenInformationClass,
324 TokenInformation,
325 TokenInformationLength,
326 ReturnLength)
327 );
328}
329
330BOOL WINAPI lookup_account_sid (
331 LPCTSTR lpSystemName,
332 PSID Sid,
333 LPTSTR Name,
334 LPDWORD cbName,
335 LPTSTR DomainName,
336 LPDWORD cbDomainName,
337 PSID_NAME_USE peUse)
338{
9785d95b 339 static LookupAccountSid_Proc s_pfn_Lookup_Account_Sid = NULL;
f60ae425
BK
340 HMODULE hm_advapi32 = NULL;
341 if (is_windows_9x () == TRUE)
342 {
343 return FALSE;
344 }
9785d95b
BK
345 if (g_b_init_lookup_account_sid == 0)
346 {
347 g_b_init_lookup_account_sid = 1;
348 hm_advapi32 = LoadLibrary ("Advapi32.dll");
349 s_pfn_Lookup_Account_Sid =
350 (LookupAccountSid_Proc) GetProcAddress (hm_advapi32, LookupAccountSid_Name);
351 }
352 if (s_pfn_Lookup_Account_Sid == NULL)
f60ae425
BK
353 {
354 return FALSE;
355 }
356 return (
9785d95b 357 s_pfn_Lookup_Account_Sid (
f60ae425
BK
358 lpSystemName,
359 Sid,
360 Name,
361 cbName,
362 DomainName,
363 cbDomainName,
364 peUse)
365 );
366}
367
368PSID_IDENTIFIER_AUTHORITY WINAPI get_sid_identifier_authority (
369 PSID pSid)
370{
9785d95b 371 static GetSidIdentifierAuthority_Proc s_pfn_Get_Sid_Identifier_Authority = NULL;
f60ae425
BK
372 HMODULE hm_advapi32 = NULL;
373 if (is_windows_9x () == TRUE)
374 {
375 return NULL;
376 }
9785d95b
BK
377 if (g_b_init_get_sid_identifier_authority == 0)
378 {
379 g_b_init_get_sid_identifier_authority = 1;
380 hm_advapi32 = LoadLibrary ("Advapi32.dll");
381 s_pfn_Get_Sid_Identifier_Authority =
382 (GetSidIdentifierAuthority_Proc) GetProcAddress (
383 hm_advapi32, "GetSidIdentifierAuthority");
384 }
385 if (s_pfn_Get_Sid_Identifier_Authority == NULL)
f60ae425
BK
386 {
387 return NULL;
388 }
9785d95b 389 return (s_pfn_Get_Sid_Identifier_Authority (pSid));
f60ae425
BK
390}
391
c617afce
EZ
392PDWORD WINAPI get_sid_sub_authority (
393 PSID pSid,
394 DWORD n)
395{
396 static GetSidSubAuthority_Proc s_pfn_Get_Sid_Sub_Authority = NULL;
6811b9f4 397 static DWORD zero = 0U;
c617afce
EZ
398 HMODULE hm_advapi32 = NULL;
399 if (is_windows_9x () == TRUE)
400 {
6811b9f4 401 return &zero;
c617afce
EZ
402 }
403 if (g_b_init_get_sid_sub_authority == 0)
404 {
405 g_b_init_get_sid_sub_authority = 1;
406 hm_advapi32 = LoadLibrary ("Advapi32.dll");
407 s_pfn_Get_Sid_Sub_Authority =
408 (GetSidSubAuthority_Proc) GetProcAddress (
409 hm_advapi32, "GetSidSubAuthority");
410 }
411 if (s_pfn_Get_Sid_Sub_Authority == NULL)
412 {
6811b9f4 413 return &zero;
c617afce
EZ
414 }
415 return (s_pfn_Get_Sid_Sub_Authority (pSid, n));
416}
417
418PUCHAR WINAPI get_sid_sub_authority_count (
419 PSID pSid)
420{
421 static GetSidSubAuthorityCount_Proc s_pfn_Get_Sid_Sub_Authority_Count = NULL;
6811b9f4 422 static UCHAR zero = 0U;
c617afce
EZ
423 HMODULE hm_advapi32 = NULL;
424 if (is_windows_9x () == TRUE)
425 {
6811b9f4 426 return &zero;
c617afce
EZ
427 }
428 if (g_b_init_get_sid_sub_authority_count == 0)
429 {
430 g_b_init_get_sid_sub_authority_count = 1;
431 hm_advapi32 = LoadLibrary ("Advapi32.dll");
432 s_pfn_Get_Sid_Sub_Authority_Count =
433 (GetSidSubAuthorityCount_Proc) GetProcAddress (
434 hm_advapi32, "GetSidSubAuthorityCount");
435 }
436 if (s_pfn_Get_Sid_Sub_Authority_Count == NULL)
437 {
6811b9f4 438 return &zero;
c617afce
EZ
439 }
440 return (s_pfn_Get_Sid_Sub_Authority_Count (pSid));
441}
442
8aaaec6b
EZ
443BOOL WINAPI get_file_security (
444 LPCTSTR lpFileName,
445 SECURITY_INFORMATION RequestedInformation,
446 PSECURITY_DESCRIPTOR pSecurityDescriptor,
447 DWORD nLength,
448 LPDWORD lpnLengthNeeded)
449{
450 static GetFileSecurity_Proc s_pfn_Get_File_Security = NULL;
451 HMODULE hm_advapi32 = NULL;
452 if (is_windows_9x () == TRUE)
453 {
454 return FALSE;
455 }
456 if (g_b_init_get_file_security == 0)
457 {
458 g_b_init_get_file_security = 1;
459 hm_advapi32 = LoadLibrary ("Advapi32.dll");
460 s_pfn_Get_File_Security =
461 (GetFileSecurity_Proc) GetProcAddress (
462 hm_advapi32, GetFileSecurity_Name);
463 }
464 if (s_pfn_Get_File_Security == NULL)
465 {
466 return FALSE;
467 }
468 return (s_pfn_Get_File_Security (lpFileName, RequestedInformation,
469 pSecurityDescriptor, nLength,
470 lpnLengthNeeded));
471}
472
473BOOL WINAPI get_security_descriptor_owner (
474 PSECURITY_DESCRIPTOR pSecurityDescriptor,
475 PSID *pOwner,
476 LPBOOL lpbOwnerDefaulted)
477{
478 static GetSecurityDescriptorOwner_Proc s_pfn_Get_Security_Descriptor_Owner = NULL;
479 HMODULE hm_advapi32 = NULL;
480 if (is_windows_9x () == TRUE)
481 {
482 return FALSE;
483 }
484 if (g_b_init_get_security_descriptor_owner == 0)
485 {
486 g_b_init_get_security_descriptor_owner = 1;
487 hm_advapi32 = LoadLibrary ("Advapi32.dll");
488 s_pfn_Get_Security_Descriptor_Owner =
489 (GetSecurityDescriptorOwner_Proc) GetProcAddress (
490 hm_advapi32, "GetSecurityDescriptorOwner");
491 }
492 if (s_pfn_Get_Security_Descriptor_Owner == NULL)
493 {
494 return FALSE;
495 }
496 return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor, pOwner,
497 lpbOwnerDefaulted));
498}
499
500BOOL WINAPI get_security_descriptor_group (
501 PSECURITY_DESCRIPTOR pSecurityDescriptor,
502 PSID *pGroup,
503 LPBOOL lpbGroupDefaulted)
504{
505 static GetSecurityDescriptorGroup_Proc s_pfn_Get_Security_Descriptor_Group = NULL;
506 HMODULE hm_advapi32 = NULL;
507 if (is_windows_9x () == TRUE)
508 {
509 return FALSE;
510 }
511 if (g_b_init_get_security_descriptor_group == 0)
512 {
513 g_b_init_get_security_descriptor_group = 1;
514 hm_advapi32 = LoadLibrary ("Advapi32.dll");
515 s_pfn_Get_Security_Descriptor_Group =
516 (GetSecurityDescriptorGroup_Proc) GetProcAddress (
517 hm_advapi32, "GetSecurityDescriptorGroup");
518 }
519 if (s_pfn_Get_Security_Descriptor_Group == NULL)
520 {
521 return FALSE;
522 }
523 return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor, pGroup,
524 lpbGroupDefaulted));
525}
526
527BOOL WINAPI is_valid_sid (
528 PSID sid)
529{
530 static IsValidSid_Proc s_pfn_Is_Valid_Sid = NULL;
531 HMODULE hm_advapi32 = NULL;
532 if (is_windows_9x () == TRUE)
533 {
534 return FALSE;
535 }
536 if (g_b_init_is_valid_sid == 0)
537 {
538 g_b_init_is_valid_sid = 1;
539 hm_advapi32 = LoadLibrary ("Advapi32.dll");
540 s_pfn_Is_Valid_Sid =
541 (IsValidSid_Proc) GetProcAddress (
542 hm_advapi32, "IsValidSid");
543 }
544 if (s_pfn_Is_Valid_Sid == NULL)
545 {
546 return FALSE;
547 }
548 return (s_pfn_Is_Valid_Sid (sid));
549}
550
f60ae425
BK
551/*
552 END: Wrapper functions around OpenProcessToken
553 and other functions in advapi32.dll that are only
554 supported in Windows NT / 2k / XP
555*/
556
557\f
18e070ac
AI
558/* Equivalent of strerror for W32 error codes. */
559char *
560w32_strerror (int error_no)
561{
562 static char buf[500];
563
564 if (error_no == 0)
565 error_no = GetLastError ();
566
567 buf[0] = '\0';
568 if (!FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL,
569 error_no,
570 0, /* choose most suitable language */
571 buf, sizeof (buf), NULL))
572 sprintf (buf, "w32 error %u", error_no);
573 return buf;
574}
575
ed91b2ad
EZ
576/* Return 1 if P is a valid pointer to an object of size SIZE. Return
577 0 if P is NOT a valid pointer. Return -1 if we cannot validate P.
578
579 This is called from alloc.c:valid_pointer_p. */
580int
581w32_valid_pointer_p (void *p, int size)
582{
583 SIZE_T done;
584 HANDLE h = OpenProcess (PROCESS_VM_READ, FALSE, GetCurrentProcessId ());
585
586 if (h)
587 {
588 unsigned char *buf = alloca (size);
589 int retval = ReadProcessMemory (h, p, buf, size, &done);
590
591 CloseHandle (h);
592 return retval;
593 }
594 else
595 return -1;
596}
597
76b3903d 598static char startup_dir[MAXPATHLEN];
00b3b7b3 599
95ed0025 600/* Get the current working directory. */
480b0c5b 601char *
95ed0025
RS
602getwd (char *dir)
603{
76b3903d 604#if 0
480b0c5b
GV
605 if (GetCurrentDirectory (MAXPATHLEN, dir) > 0)
606 return dir;
607 return NULL;
76b3903d
GV
608#else
609 /* Emacs doesn't actually change directory itself, and we want to
610 force our real wd to be where emacs.exe is to avoid unnecessary
611 conflicts when trying to rename or delete directories. */
612 strcpy (dir, startup_dir);
613 return dir;
614#endif
95ed0025
RS
615}
616
480b0c5b 617#ifndef HAVE_SOCKETS
95ed0025
RS
618/* Emulate gethostname. */
619int
620gethostname (char *buffer, int size)
621{
177c0ea7 622 /* NT only allows small host names, so the buffer is
95ed0025
RS
623 certainly large enough. */
624 return !GetComputerName (buffer, &size);
625}
480b0c5b 626#endif /* HAVE_SOCKETS */
95ed0025
RS
627
628/* Emulate getloadavg. */
629int
630getloadavg (double loadavg[], int nelem)
631{
632 int i;
633
634 /* A faithful emulation is going to have to be saved for a rainy day. */
177c0ea7 635 for (i = 0; i < nelem; i++)
95ed0025
RS
636 {
637 loadavg[i] = 0.0;
638 }
639 return i;
640}
641
480b0c5b 642/* Emulate getpwuid, getpwnam and others. */
95ed0025 643
051fe60d
GV
644#define PASSWD_FIELD_SIZE 256
645
07f7980a
EZ
646static char dflt_passwd_name[PASSWD_FIELD_SIZE];
647static char dflt_passwd_passwd[PASSWD_FIELD_SIZE];
648static char dflt_passwd_gecos[PASSWD_FIELD_SIZE];
649static char dflt_passwd_dir[PASSWD_FIELD_SIZE];
650static char dflt_passwd_shell[PASSWD_FIELD_SIZE];
95ed0025 651
07f7980a 652static struct passwd dflt_passwd =
95ed0025 653{
07f7980a
EZ
654 dflt_passwd_name,
655 dflt_passwd_passwd,
95ed0025
RS
656 0,
657 0,
658 0,
07f7980a
EZ
659 dflt_passwd_gecos,
660 dflt_passwd_dir,
661 dflt_passwd_shell,
95ed0025
RS
662};
663
07f7980a
EZ
664static char dflt_group_name[GNLEN+1];
665
666static struct group dflt_group =
3d19b645 667{
07f7980a
EZ
668 /* When group information is not available, we return this as the
669 group for all files. */
670 dflt_group_name,
671 0,
3d19b645
LH
672};
673
177c0ea7
JB
674int
675getuid ()
676{
07f7980a 677 return dflt_passwd.pw_uid;
480b0c5b
GV
678}
679
177c0ea7
JB
680int
681geteuid ()
682{
480b0c5b
GV
683 /* I could imagine arguing for checking to see whether the user is
684 in the Administrators group and returning a UID of 0 for that
685 case, but I don't know how wise that would be in the long run. */
177c0ea7 686 return getuid ();
480b0c5b
GV
687}
688
177c0ea7
JB
689int
690getgid ()
691{
07f7980a 692 return dflt_passwd.pw_gid;
480b0c5b
GV
693}
694
177c0ea7
JB
695int
696getegid ()
697{
480b0c5b
GV
698 return getgid ();
699}
700
95ed0025
RS
701struct passwd *
702getpwuid (int uid)
703{
07f7980a
EZ
704 if (uid == dflt_passwd.pw_uid)
705 return &dflt_passwd;
480b0c5b 706 return NULL;
95ed0025
RS
707}
708
3d19b645
LH
709struct group *
710getgrgid (gid_t gid)
711{
07f7980a 712 return &dflt_group;
3d19b645
LH
713}
714
95ed0025
RS
715struct passwd *
716getpwnam (char *name)
717{
718 struct passwd *pw;
177c0ea7 719
95ed0025
RS
720 pw = getpwuid (getuid ());
721 if (!pw)
722 return pw;
723
05131107 724 if (xstrcasecmp (name, pw->pw_name))
95ed0025
RS
725 return NULL;
726
727 return pw;
728}
729
480b0c5b
GV
730void
731init_user_info ()
95ed0025 732{
480b0c5b
GV
733 /* Find the user's real name by opening the process token and
734 looking up the name associated with the user-sid in that token.
735
736 Use the relative portion of the identifier authority value from
737 the user-sid as the user id value (same for group id using the
738 primary group sid from the process token). */
739
07f7980a
EZ
740 char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
741 DWORD ulength = sizeof (uname), dlength = sizeof (domain), trash;
742 DWORD glength = sizeof (gname);
10aabbf9
JB
743 HANDLE token = NULL;
744 SID_NAME_USE user_type;
634d3003
EZ
745 unsigned char buf[1024];
746 TOKEN_USER user_token;
747 TOKEN_PRIMARY_GROUP group_token;
10aabbf9
JB
748
749 if (open_process_token (GetCurrentProcess (), TOKEN_QUERY, &token)
750 && get_token_information (token, TokenUser,
634d3003
EZ
751 (PVOID)buf, sizeof (buf), &trash)
752 && (memcpy (&user_token, buf, sizeof (user_token)),
07f7980a 753 lookup_account_sid (NULL, user_token.User.Sid, uname, &ulength,
634d3003 754 domain, &dlength, &user_type)))
d1c1c3d2 755 {
07f7980a 756 strcpy (dflt_passwd.pw_name, uname);
c617afce 757 /* Determine a reasonable uid value. */
05131107 758 if (xstrcasecmp ("administrator", uname) == 0)
480b0c5b 759 {
07f7980a
EZ
760 dflt_passwd.pw_uid = 500; /* well-known Administrator uid */
761 dflt_passwd.pw_gid = 513; /* well-known None gid */
480b0c5b
GV
762 }
763 else
764 {
ce0ee994
EZ
765 /* Use the last sub-authority value of the RID, the relative
766 portion of the SID, as user/group ID. */
8aaaec6b 767 dflt_passwd.pw_uid = get_rid (user_token.User.Sid);
480b0c5b 768
8aaaec6b 769 /* Get group id and name. */
f60ae425 770 if (get_token_information (token, TokenPrimaryGroup,
634d3003 771 (PVOID)buf, sizeof (buf), &trash))
480b0c5b 772 {
634d3003 773 memcpy (&group_token, buf, sizeof (group_token));
8aaaec6b 774 dflt_passwd.pw_gid = get_rid (group_token.PrimaryGroup);
07f7980a
EZ
775 dlength = sizeof (domain);
776 if (lookup_account_sid (NULL, group_token.PrimaryGroup,
777 gname, &glength, NULL, &dlength,
778 &user_type))
779 strcpy (dflt_group_name, gname);
480b0c5b
GV
780 }
781 else
07f7980a 782 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
480b0c5b
GV
783 }
784 }
785 /* If security calls are not supported (presumably because we
10aabbf9 786 are running under Windows 95), fallback to this. */
07f7980a 787 else if (GetUserName (uname, &ulength))
480b0c5b 788 {
07f7980a 789 strcpy (dflt_passwd.pw_name, uname);
05131107 790 if (xstrcasecmp ("administrator", uname) == 0)
07f7980a 791 dflt_passwd.pw_uid = 0;
480b0c5b 792 else
07f7980a
EZ
793 dflt_passwd.pw_uid = 123;
794 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
480b0c5b
GV
795 }
796 else
797 {
07f7980a
EZ
798 strcpy (dflt_passwd.pw_name, "unknown");
799 dflt_passwd.pw_uid = 123;
800 dflt_passwd.pw_gid = 123;
d1c1c3d2 801 }
07f7980a 802 dflt_group.gr_gid = dflt_passwd.pw_gid;
95ed0025 803
480b0c5b
GV
804 /* Ensure HOME and SHELL are defined. */
805 if (getenv ("HOME") == NULL)
ca149beb 806 abort ();
480b0c5b 807 if (getenv ("SHELL") == NULL)
ca149beb 808 abort ();
95ed0025 809
480b0c5b 810 /* Set dir and shell from environment variables. */
07f7980a
EZ
811 strcpy (dflt_passwd.pw_dir, getenv ("HOME"));
812 strcpy (dflt_passwd.pw_shell, getenv ("SHELL"));
bd4a449f 813
480b0c5b
GV
814 if (token)
815 CloseHandle (token);
95ed0025
RS
816}
817
95ed0025 818int
480b0c5b 819random ()
95ed0025 820{
480b0c5b
GV
821 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
822 return ((rand () << 15) | rand ());
95ed0025
RS
823}
824
95ed0025 825void
480b0c5b 826srandom (int seed)
95ed0025 827{
480b0c5b 828 srand (seed);
95ed0025
RS
829}
830
76b3903d 831
cbe39279
RS
832/* Normalize filename by converting all path separators to
833 the specified separator. Also conditionally convert upper
834 case path name components to lower case. */
835
836static void
837normalize_filename (fp, path_sep)
838 register char *fp;
839 char path_sep;
840{
841 char sep;
842 char *elem;
843
5162ffce
MB
844 /* Always lower-case drive letters a-z, even if the filesystem
845 preserves case in filenames.
846 This is so filenames can be compared by string comparison
847 functions that are case-sensitive. Even case-preserving filesystems
848 do not distinguish case in drive letters. */
849 if (fp[1] == ':' && *fp >= 'A' && *fp <= 'Z')
850 {
851 *fp += 'a' - 'A';
852 fp += 2;
853 }
854
fbd6baed 855 if (NILP (Vw32_downcase_file_names))
cbe39279
RS
856 {
857 while (*fp)
858 {
859 if (*fp == '/' || *fp == '\\')
860 *fp = path_sep;
861 fp++;
862 }
863 return;
864 }
865
866 sep = path_sep; /* convert to this path separator */
867 elem = fp; /* start of current path element */
868
869 do {
870 if (*fp >= 'a' && *fp <= 'z')
871 elem = 0; /* don't convert this element */
872
873 if (*fp == 0 || *fp == ':')
874 {
875 sep = *fp; /* restore current separator (or 0) */
876 *fp = '/'; /* after conversion of this element */
877 }
878
879 if (*fp == '/' || *fp == '\\')
880 {
881 if (elem && elem != fp)
882 {
883 *fp = 0; /* temporary end of string */
884 _strlwr (elem); /* while we convert to lower case */
885 }
886 *fp = sep; /* convert (or restore) path separator */
887 elem = fp + 1; /* next element starts after separator */
888 sep = path_sep;
889 }
890 } while (*fp++);
891}
892
480b0c5b 893/* Destructively turn backslashes into slashes. */
95ed0025 894void
480b0c5b
GV
895dostounix_filename (p)
896 register char *p;
95ed0025 897{
cbe39279 898 normalize_filename (p, '/');
95ed0025
RS
899}
900
480b0c5b 901/* Destructively turn slashes into backslashes. */
95ed0025 902void
480b0c5b
GV
903unixtodos_filename (p)
904 register char *p;
95ed0025 905{
cbe39279 906 normalize_filename (p, '\\');
95ed0025
RS
907}
908
480b0c5b
GV
909/* Remove all CR's that are followed by a LF.
910 (From msdos.c...probably should figure out a way to share it,
911 although this code isn't going to ever change.) */
35f0d482 912int
480b0c5b
GV
913crlf_to_lf (n, buf)
914 register int n;
915 register unsigned char *buf;
35f0d482 916{
480b0c5b
GV
917 unsigned char *np = buf;
918 unsigned char *startp = buf;
919 unsigned char *endp = buf + n;
35f0d482 920
480b0c5b
GV
921 if (n == 0)
922 return n;
923 while (buf < endp - 1)
95ed0025 924 {
480b0c5b
GV
925 if (*buf == 0x0d)
926 {
927 if (*(++buf) != 0x0a)
928 *np++ = 0x0d;
929 }
930 else
931 *np++ = *buf++;
95ed0025 932 }
480b0c5b
GV
933 if (buf < endp)
934 *np++ = *buf++;
935 return np - startp;
95ed0025
RS
936}
937
76b3903d
GV
938/* Parse the root part of file name, if present. Return length and
939 optionally store pointer to char after root. */
940static int
941parse_root (char * name, char ** pPath)
942{
943 char * start = name;
944
945 if (name == NULL)
946 return 0;
947
948 /* find the root name of the volume if given */
949 if (isalpha (name[0]) && name[1] == ':')
950 {
951 /* skip past drive specifier */
952 name += 2;
953 if (IS_DIRECTORY_SEP (name[0]))
954 name++;
955 }
956 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
957 {
958 int slashes = 2;
959 name += 2;
960 do
961 {
962 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
963 break;
964 name++;
965 }
966 while ( *name );
967 if (IS_DIRECTORY_SEP (name[0]))
968 name++;
969 }
970
971 if (pPath)
972 *pPath = name;
973
974 return name - start;
975}
976
977/* Get long base name for name; name is assumed to be absolute. */
978static int
979get_long_basename (char * name, char * buf, int size)
980{
981 WIN32_FIND_DATA find_data;
982 HANDLE dir_handle;
983 int len = 0;
984
9ab8560d 985 /* must be valid filename, no wild cards or other invalid characters */
22189f79 986 if (_mbspbrk (name, "*?|<>\""))
bb1584c8
RS
987 return 0;
988
76b3903d
GV
989 dir_handle = FindFirstFile (name, &find_data);
990 if (dir_handle != INVALID_HANDLE_VALUE)
991 {
992 if ((len = strlen (find_data.cFileName)) < size)
993 memcpy (buf, find_data.cFileName, len + 1);
994 else
995 len = 0;
996 FindClose (dir_handle);
997 }
998 return len;
999}
1000
1001/* Get long name for file, if possible (assumed to be absolute). */
1002BOOL
1003w32_get_long_filename (char * name, char * buf, int size)
1004{
1005 char * o = buf;
1006 char * p;
1007 char * q;
1008 char full[ MAX_PATH ];
1009 int len;
1010
1011 len = strlen (name);
1012 if (len >= MAX_PATH)
1013 return FALSE;
1014
1015 /* Use local copy for destructive modification. */
1016 memcpy (full, name, len+1);
1017 unixtodos_filename (full);
1018
1019 /* Copy root part verbatim. */
1020 len = parse_root (full, &p);
1021 memcpy (o, full, len);
1022 o += len;
4f8ac0b2 1023 *o = '\0';
76b3903d
GV
1024 size -= len;
1025
4f8ac0b2 1026 while (p != NULL && *p)
76b3903d
GV
1027 {
1028 q = p;
1029 p = strchr (q, '\\');
1030 if (p) *p = '\0';
1031 len = get_long_basename (full, o, size);
1032 if (len > 0)
1033 {
1034 o += len;
1035 size -= len;
1036 if (p != NULL)
1037 {
1038 *p++ = '\\';
1039 if (size < 2)
1040 return FALSE;
1041 *o++ = '\\';
1042 size--;
1043 *o = '\0';
1044 }
1045 }
1046 else
1047 return FALSE;
1048 }
76b3903d
GV
1049
1050 return TRUE;
1051}
1052
9d3355d1
GV
1053int
1054is_unc_volume (const char *filename)
1055{
1056 const char *ptr = filename;
1057
1058 if (!IS_DIRECTORY_SEP (ptr[0]) || !IS_DIRECTORY_SEP (ptr[1]) || !ptr[2])
1059 return 0;
1060
22189f79 1061 if (_mbspbrk (ptr + 2, "*?|<>\"\\/"))
9d3355d1
GV
1062 return 0;
1063
1064 return 1;
1065}
76b3903d 1066
95ed0025
RS
1067/* Routines that are no-ops on NT but are defined to get Emacs to compile. */
1068
177c0ea7
JB
1069int
1070sigsetmask (int signal_mask)
1071{
95ed0025
RS
1072 return 0;
1073}
1074
177c0ea7
JB
1075int
1076sigmask (int sig)
1077{
8f900f6e
AI
1078 return 0;
1079}
1080
177c0ea7
JB
1081int
1082sigblock (int sig)
1083{
95ed0025
RS
1084 return 0;
1085}
1086
177c0ea7
JB
1087int
1088sigunblock (int sig)
1089{
8f900f6e
AI
1090 return 0;
1091}
1092
177c0ea7
JB
1093int
1094setpgrp (int pid, int gid)
1095{
95ed0025
RS
1096 return 0;
1097}
1098
177c0ea7
JB
1099int
1100alarm (int seconds)
1101{
95ed0025
RS
1102 return 0;
1103}
1104
480b0c5b 1105#define REG_ROOT "SOFTWARE\\GNU\\Emacs"
f332b293 1106
177c0ea7 1107LPBYTE
fbd6baed 1108w32_get_resource (key, lpdwtype)
f332b293
GV
1109 char *key;
1110 LPDWORD lpdwtype;
1111{
1112 LPBYTE lpvalue;
1113 HKEY hrootkey = NULL;
1114 DWORD cbData;
177c0ea7
JB
1115
1116 /* Check both the current user and the local machine to see if
f332b293 1117 we have any resources. */
177c0ea7 1118
f332b293
GV
1119 if (RegOpenKeyEx (HKEY_CURRENT_USER, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
1120 {
1121 lpvalue = NULL;
1122
177c0ea7
JB
1123 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
1124 && (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL
f332b293
GV
1125 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
1126 {
4da4d9bb 1127 RegCloseKey (hrootkey);
f332b293
GV
1128 return (lpvalue);
1129 }
1130
70fdbb46 1131 xfree (lpvalue);
177c0ea7 1132
f332b293 1133 RegCloseKey (hrootkey);
177c0ea7
JB
1134 }
1135
f332b293
GV
1136 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
1137 {
1138 lpvalue = NULL;
177c0ea7 1139
76b3903d
GV
1140 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
1141 && (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL
1142 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
f332b293 1143 {
4da4d9bb 1144 RegCloseKey (hrootkey);
f332b293
GV
1145 return (lpvalue);
1146 }
177c0ea7 1147
70fdbb46 1148 xfree (lpvalue);
177c0ea7 1149
f332b293 1150 RegCloseKey (hrootkey);
177c0ea7
JB
1151 }
1152
f332b293
GV
1153 return (NULL);
1154}
1155
75b08edb
GV
1156char *get_emacs_configuration (void);
1157extern Lisp_Object Vsystem_configuration;
1158
f332b293 1159void
aa7b87b0 1160init_environment (char ** argv)
f332b293 1161{
b3308d2e
KH
1162 static const char * const tempdirs[] = {
1163 "$TMPDIR", "$TEMP", "$TMP", "c:/"
1164 };
2d5324c5 1165
b3308d2e 1166 int i;
2d5324c5 1167
b3308d2e
KH
1168 const int imax = sizeof (tempdirs) / sizeof (tempdirs[0]);
1169
1170 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
1171 temporary files and assume "/tmp" if $TMPDIR is unset, which
1172 will break on DOS/Windows. Refuse to work if we cannot find
1173 a directory, not even "c:/", usable for that purpose. */
1174 for (i = 0; i < imax ; i++)
1175 {
1176 const char *tmp = tempdirs[i];
1177
1178 if (*tmp == '$')
1179 tmp = getenv (tmp + 1);
1180 /* Note that `access' can lie to us if the directory resides on a
1181 read-only filesystem, like CD-ROM or a write-protected floppy.
1182 The only way to be really sure is to actually create a file and
1183 see if it succeeds. But I think that's too much to ask. */
a302c7ae 1184 if (tmp && _access (tmp, D_OK) == 0)
b3308d2e
KH
1185 {
1186 char * var = alloca (strlen (tmp) + 8);
1187 sprintf (var, "TMPDIR=%s", tmp);
aca583b2 1188 _putenv (strdup (var));
b3308d2e
KH
1189 break;
1190 }
1191 }
1192 if (i >= imax)
1193 cmd_error_internal
1194 (Fcons (Qerror,
1195 Fcons (build_string ("no usable temporary directories found!!"),
1196 Qnil)),
1197 "While setting TMPDIR: ");
1198
ca149beb
AI
1199 /* Check for environment variables and use registry settings if they
1200 don't exist. Fallback on default values where applicable. */
f332b293 1201 {
480b0c5b
GV
1202 int i;
1203 LPBYTE lpval;
1204 DWORD dwType;
69fb0241 1205 char locale_name[32];
2d5324c5
JR
1206 struct stat ignored;
1207 char default_home[MAX_PATH];
f332b293 1208
e00b99c8 1209 static const struct env_entry
ca149beb
AI
1210 {
1211 char * name;
1212 char * def_value;
e00b99c8 1213 } dflt_envvars[] =
ca149beb
AI
1214 {
1215 {"HOME", "C:/"},
1216 {"PRELOAD_WINSOCK", NULL},
1217 {"emacs_dir", "C:/emacs"},
cc14250a 1218 {"EMACSLOADPATH", "%emacs_dir%/site-lisp;%emacs_dir%/../site-lisp;%emacs_dir%/lisp;%emacs_dir%/leim"},
ca149beb
AI
1219 {"SHELL", "%emacs_dir%/bin/cmdproxy.exe"},
1220 {"EMACSDATA", "%emacs_dir%/etc"},
1221 {"EMACSPATH", "%emacs_dir%/bin"},
76b3903d 1222 /* We no longer set INFOPATH because Info-default-directory-list
ca149beb
AI
1223 is then ignored. */
1224 /* {"INFOPATH", "%emacs_dir%/info"}, */
1225 {"EMACSDOC", "%emacs_dir%/etc"},
69fb0241
JR
1226 {"TERM", "cmd"},
1227 {"LANG", NULL},
480b0c5b
GV
1228 };
1229
e00b99c8
EZ
1230#define N_ENV_VARS sizeof(dflt_envvars)/sizeof(dflt_envvars[0])
1231
1232 /* We need to copy dflt_envvars[] and work on the copy because we
1233 don't want the dumped Emacs to inherit the values of
1234 environment variables we saw during dumping (which could be on
1235 a different system). The defaults above must be left intact. */
1236 struct env_entry env_vars[N_ENV_VARS];
1237
1238 for (i = 0; i < N_ENV_VARS; i++)
1239 env_vars[i] = dflt_envvars[i];
1240
2d5324c5
JR
1241 /* For backwards compatibility, check if a .emacs file exists in C:/
1242 If not, then we can try to default to the appdata directory under the
1243 user's profile, which is more likely to be writable. */
1244 if (stat ("C:/.emacs", &ignored) < 0)
1245 {
1246 HRESULT profile_result;
1247 /* Dynamically load ShGetFolderPath, as it won't exist on versions
1248 of Windows 95 and NT4 that have not been updated to include
1249 MSIE 5. Also we don't link with shell32.dll by default. */
1250 HMODULE shell32_dll;
1251 ShGetFolderPath_fn get_folder_path;
1252 shell32_dll = GetModuleHandle ("shell32.dll");
1253 get_folder_path = (ShGetFolderPath_fn)
1254 GetProcAddress (shell32_dll, "SHGetFolderPathA");
1255
1256 if (get_folder_path != NULL)
1257 {
1258 profile_result = get_folder_path (NULL, CSIDL_APPDATA, NULL,
1259 0, default_home);
1260
1261 /* If we can't get the appdata dir, revert to old behaviour. */
1262 if (profile_result == S_OK)
1263 env_vars[0].def_value = default_home;
1264 }
1265
1266 /* Unload shell32.dll, it is not needed anymore. */
1267 FreeLibrary (shell32_dll);
1268 }
1269
69fb0241
JR
1270 /* Get default locale info and use it for LANG. */
1271 if (GetLocaleInfo (LOCALE_USER_DEFAULT,
1272 LOCALE_SABBREVLANGNAME | LOCALE_USE_CP_ACP,
1273 locale_name, sizeof (locale_name)))
1274 {
e00b99c8 1275 for (i = 0; i < N_ENV_VARS; i++)
69fb0241
JR
1276 {
1277 if (strcmp (env_vars[i].name, "LANG") == 0)
1278 {
1279 env_vars[i].def_value = locale_name;
1280 break;
1281 }
1282 }
1283 }
1284
ca149beb
AI
1285#define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
1286
1287 /* Treat emacs_dir specially: set it unconditionally based on our
1288 location, if it appears that we are running from the bin subdir
1289 of a standard installation. */
1290 {
1291 char *p;
1292 char modname[MAX_PATH];
1293
1294 if (!GetModuleFileName (NULL, modname, MAX_PATH))
1295 abort ();
1296 if ((p = strrchr (modname, '\\')) == NULL)
1297 abort ();
1298 *p = 0;
1299
05131107 1300 if ((p = strrchr (modname, '\\')) && xstrcasecmp (p, "\\bin") == 0)
ca149beb
AI
1301 {
1302 char buf[SET_ENV_BUF_SIZE];
1303
1304 *p = 0;
1305 for (p = modname; *p; p++)
1306 if (*p == '\\') *p = '/';
177c0ea7 1307
ca149beb 1308 _snprintf (buf, sizeof(buf)-1, "emacs_dir=%s", modname);
a302c7ae 1309 _putenv (strdup (buf));
ca149beb 1310 }
950090be
JR
1311 /* Handle running emacs from the build directory: src/oo-spd/i386/ */
1312
1313 /* FIXME: should use substring of get_emacs_configuration ().
1314 But I don't think the Windows build supports alpha, mips etc
1315 anymore, so have taken the easy option for now. */
05131107 1316 else if (p && xstrcasecmp (p, "\\i386") == 0)
950090be
JR
1317 {
1318 *p = 0;
1319 p = strrchr (modname, '\\');
1320 if (p != NULL)
1321 {
1322 *p = 0;
1323 p = strrchr (modname, '\\');
05131107 1324 if (p && xstrcasecmp (p, "\\src") == 0)
950090be
JR
1325 {
1326 char buf[SET_ENV_BUF_SIZE];
1327
1328 *p = 0;
1329 for (p = modname; *p; p++)
1330 if (*p == '\\') *p = '/';
1331
1332 _snprintf (buf, sizeof(buf)-1, "emacs_dir=%s", modname);
1333 _putenv (strdup (buf));
1334 }
1335 }
1336 }
ca149beb
AI
1337 }
1338
e00b99c8 1339 for (i = 0; i < N_ENV_VARS; i++)
f332b293 1340 {
ca149beb 1341 if (!getenv (env_vars[i].name))
480b0c5b 1342 {
ca149beb 1343 int dont_free = 0;
480b0c5b 1344
aa5ee2a3
JB
1345 if ((lpval = w32_get_resource (env_vars[i].name, &dwType)) == NULL
1346 /* Also ignore empty environment variables. */
1347 || *lpval == 0)
ca149beb 1348 {
70fdbb46 1349 xfree (lpval);
ca149beb
AI
1350 lpval = env_vars[i].def_value;
1351 dwType = REG_EXPAND_SZ;
1352 dont_free = 1;
480b0c5b 1353 }
ca149beb
AI
1354
1355 if (lpval)
480b0c5b 1356 {
892eb237 1357 char buf1[SET_ENV_BUF_SIZE], buf2[SET_ENV_BUF_SIZE];
ca149beb 1358
892eb237
EZ
1359 if (dwType == REG_EXPAND_SZ)
1360 ExpandEnvironmentStrings ((LPSTR) lpval, buf1, sizeof(buf1));
ca149beb 1361 else if (dwType == REG_SZ)
892eb237
EZ
1362 strcpy (buf1, lpval);
1363 if (dwType == REG_EXPAND_SZ || dwType == REG_SZ)
ca149beb 1364 {
892eb237
EZ
1365 _snprintf (buf2, sizeof(buf2)-1, "%s=%s", env_vars[i].name,
1366 buf1);
1367 _putenv (strdup (buf2));
ca149beb 1368 }
f332b293 1369
ca149beb
AI
1370 if (!dont_free)
1371 xfree (lpval);
1372 }
480b0c5b
GV
1373 }
1374 }
1375 }
1376
75b08edb
GV
1377 /* Rebuild system configuration to reflect invoking system. */
1378 Vsystem_configuration = build_string (EMACS_CONFIGURATION);
1379
76b3903d
GV
1380 /* Another special case: on NT, the PATH variable is actually named
1381 "Path" although cmd.exe (perhaps NT itself) arranges for
1382 environment variable lookup and setting to be case insensitive.
1383 However, Emacs assumes a fully case sensitive environment, so we
1384 need to change "Path" to "PATH" to match the expectations of
1385 various elisp packages. We do this by the sneaky method of
1386 modifying the string in the C runtime environ entry.
1387
1388 The same applies to COMSPEC. */
1389 {
1390 char ** envp;
1391
1392 for (envp = environ; *envp; envp++)
1393 if (_strnicmp (*envp, "PATH=", 5) == 0)
1394 memcpy (*envp, "PATH=", 5);
1395 else if (_strnicmp (*envp, "COMSPEC=", 8) == 0)
1396 memcpy (*envp, "COMSPEC=", 8);
1397 }
1398
1399 /* Remember the initial working directory for getwd, then make the
1400 real wd be the location of emacs.exe to avoid conflicts when
1401 renaming or deleting directories. (We also don't call chdir when
1402 running subprocesses for the same reason.) */
1403 if (!GetCurrentDirectory (MAXPATHLEN, startup_dir))
1404 abort ();
1405
1406 {
1407 char *p;
aa7b87b0 1408 static char modname[MAX_PATH];
76b3903d
GV
1409
1410 if (!GetModuleFileName (NULL, modname, MAX_PATH))
1411 abort ();
1412 if ((p = strrchr (modname, '\\')) == NULL)
1413 abort ();
1414 *p = 0;
1415
1416 SetCurrentDirectory (modname);
aa7b87b0
AI
1417
1418 /* Ensure argv[0] has the full path to Emacs. */
1419 *p = '\\';
1420 argv[0] = modname;
76b3903d
GV
1421 }
1422
20af4831
JR
1423 /* Determine if there is a middle mouse button, to allow parse_button
1424 to decide whether right mouse events should be mouse-2 or
1425 mouse-3. */
e0c181dd 1426 w32_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);
20af4831 1427
480b0c5b
GV
1428 init_user_info ();
1429}
1430
bf794306
EZ
1431char *
1432emacs_root_dir (void)
1433{
1434 static char root_dir[FILENAME_MAX];
1435 const char *p;
1436
1437 p = getenv ("emacs_dir");
1438 if (p == NULL)
1439 abort ();
1440 strcpy (root_dir, p);
1441 root_dir[parse_root (root_dir, NULL)] = '\0';
1442 dostounix_filename (root_dir);
1443 return root_dir;
1444}
1445
480b0c5b
GV
1446/* We don't have scripts to automatically determine the system configuration
1447 for Emacs before it's compiled, and we don't want to have to make the
1448 user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
1449 routine. */
1450
480b0c5b
GV
1451char *
1452get_emacs_configuration (void)
1453{
1454 char *arch, *oem, *os;
c5247da2 1455 int build_num;
a302c7ae 1456 static char configuration_buffer[32];
480b0c5b
GV
1457
1458 /* Determine the processor type. */
177c0ea7 1459 switch (get_processor_type ())
480b0c5b
GV
1460 {
1461
1462#ifdef PROCESSOR_INTEL_386
1463 case PROCESSOR_INTEL_386:
1464 case PROCESSOR_INTEL_486:
1465 case PROCESSOR_INTEL_PENTIUM:
1466 arch = "i386";
1467 break;
1468#endif
1469
480b0c5b
GV
1470#ifdef PROCESSOR_MIPS_R2000
1471 case PROCESSOR_MIPS_R2000:
1472 case PROCESSOR_MIPS_R3000:
1473 case PROCESSOR_MIPS_R4000:
1474 arch = "mips";
1475 break;
1476#endif
1477
1478#ifdef PROCESSOR_ALPHA_21064
1479 case PROCESSOR_ALPHA_21064:
1480 arch = "alpha";
1481 break;
1482#endif
1483
1484 default:
1485 arch = "unknown";
1486 break;
f332b293 1487 }
480b0c5b 1488
a302c7ae
AI
1489 /* Use the OEM field to reflect the compiler/library combination. */
1490#ifdef _MSC_VER
1491#define COMPILER_NAME "msvc"
1492#else
1493#ifdef __GNUC__
1494#define COMPILER_NAME "mingw"
1495#else
1496#define COMPILER_NAME "unknown"
1497#endif
1498#endif
1499 oem = COMPILER_NAME;
480b0c5b 1500
c5247da2
GV
1501 switch (osinfo_cache.dwPlatformId) {
1502 case VER_PLATFORM_WIN32_NT:
1503 os = "nt";
1504 build_num = osinfo_cache.dwBuildNumber;
1505 break;
1506 case VER_PLATFORM_WIN32_WINDOWS:
1507 if (osinfo_cache.dwMinorVersion == 0) {
1508 os = "windows95";
1509 } else {
1510 os = "windows98";
1511 }
1512 build_num = LOWORD (osinfo_cache.dwBuildNumber);
1513 break;
1514 case VER_PLATFORM_WIN32s:
1515 /* Not supported, should not happen. */
1516 os = "windows32s";
1517 build_num = LOWORD (osinfo_cache.dwBuildNumber);
1518 break;
1519 default:
1520 os = "unknown";
1521 build_num = 0;
1522 break;
1523 }
1524
1525 if (osinfo_cache.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1526 sprintf (configuration_buffer, "%s-%s-%s%d.%d.%d", arch, oem, os,
1527 get_w32_major_version (), get_w32_minor_version (), build_num);
1528 } else {
1529 sprintf (configuration_buffer, "%s-%s-%s.%d", arch, oem, os, build_num);
1530 }
480b0c5b 1531
480b0c5b 1532 return configuration_buffer;
f332b293
GV
1533}
1534
a302c7ae
AI
1535char *
1536get_emacs_configuration_options (void)
1537{
1538 static char options_buffer[256];
1539
1540/* Work out the effective configure options for this build. */
1541#ifdef _MSC_VER
1542#define COMPILER_VERSION "--with-msvc (%d.%02d)", _MSC_VER / 100, _MSC_VER % 100
1543#else
1544#ifdef __GNUC__
1545#define COMPILER_VERSION "--with-gcc (%d.%d)", __GNUC__, __GNUC_MINOR__
1546#else
1547#define COMPILER_VERSION ""
1548#endif
1549#endif
1550
1551 sprintf (options_buffer, COMPILER_VERSION);
1552#ifdef EMACSDEBUG
1553 strcat (options_buffer, " --no-opt");
1554#endif
1555#ifdef USER_CFLAGS
1556 strcat (options_buffer, " --cflags");
1557 strcat (options_buffer, USER_CFLAGS);
1558#endif
1559#ifdef USER_LDFLAGS
1560 strcat (options_buffer, " --ldflags");
1561 strcat (options_buffer, USER_LDFLAGS);
1562#endif
1563 return options_buffer;
1564}
1565
1566
35f0d482
KH
1567#include <sys/timeb.h>
1568
1569/* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
177c0ea7 1570void
35f0d482
KH
1571gettimeofday (struct timeval *tv, struct timezone *tz)
1572{
6e602566 1573 struct _timeb tb;
35f0d482
KH
1574 _ftime (&tb);
1575
1576 tv->tv_sec = tb.time;
1577 tv->tv_usec = tb.millitm * 1000L;
177c0ea7 1578 if (tz)
35f0d482
KH
1579 {
1580 tz->tz_minuteswest = tb.timezone; /* minutes west of Greenwich */
1581 tz->tz_dsttime = tb.dstflag; /* type of dst correction */
1582 }
1583}
35f0d482 1584
480b0c5b 1585/* ------------------------------------------------------------------------- */
fbd6baed 1586/* IO support and wrapper functions for W32 API. */
480b0c5b 1587/* ------------------------------------------------------------------------- */
95ed0025 1588
480b0c5b 1589/* Place a wrapper around the MSVC version of ctime. It returns NULL
177c0ea7 1590 on network directories, so we handle that case here.
480b0c5b
GV
1591 (Ulrich Leodolter, 1/11/95). */
1592char *
1593sys_ctime (const time_t *t)
1594{
1595 char *str = (char *) ctime (t);
1596 return (str ? str : "Sun Jan 01 00:00:00 1970");
1597}
1598
1599/* Emulate sleep...we could have done this with a define, but that
1600 would necessitate including windows.h in the files that used it.
1601 This is much easier. */
1602void
1603sys_sleep (int seconds)
1604{
1605 Sleep (seconds * 1000);
1606}
1607
76b3903d 1608/* Internal MSVC functions for low-level descriptor munging */
480b0c5b
GV
1609extern int __cdecl _set_osfhnd (int fd, long h);
1610extern int __cdecl _free_osfhnd (int fd);
1611
1612/* parallel array of private info on file handles */
1613filedesc fd_info [ MAXDESC ];
1614
76b3903d
GV
1615typedef struct volume_info_data {
1616 struct volume_info_data * next;
1617
1618 /* time when info was obtained */
1619 DWORD timestamp;
1620
1621 /* actual volume info */
1622 char * root_dir;
480b0c5b
GV
1623 DWORD serialnum;
1624 DWORD maxcomp;
1625 DWORD flags;
76b3903d
GV
1626 char * name;
1627 char * type;
1628} volume_info_data;
1629
1630/* Global referenced by various functions. */
1631static volume_info_data volume_info;
1632
1633/* Vector to indicate which drives are local and fixed (for which cached
1634 data never expires). */
1635static BOOL fixed_drives[26];
1636
1637/* Consider cached volume information to be stale if older than 10s,
1638 at least for non-local drives. Info for fixed drives is never stale. */
1639#define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
1640#define VOLINFO_STILL_VALID( root_dir, info ) \
1641 ( ( isalpha (root_dir[0]) && \
1642 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
1643 || GetTickCount () - info->timestamp < 10000 )
1644
1645/* Cache support functions. */
1646
1647/* Simple linked list with linear search is sufficient. */
1648static volume_info_data *volume_cache = NULL;
1649
1650static volume_info_data *
1651lookup_volume_info (char * root_dir)
1652{
1653 volume_info_data * info;
1654
1655 for (info = volume_cache; info; info = info->next)
05131107 1656 if (xstrcasecmp (info->root_dir, root_dir) == 0)
76b3903d
GV
1657 break;
1658 return info;
1659}
1660
1661static void
1662add_volume_info (char * root_dir, volume_info_data * info)
1663{
a302c7ae 1664 info->root_dir = xstrdup (root_dir);
76b3903d
GV
1665 info->next = volume_cache;
1666 volume_cache = info;
1667}
1668
1669
1670/* Wrapper for GetVolumeInformation, which uses caching to avoid
1671 performance penalty (~2ms on 486 for local drives, 7.5ms for local
1672 cdrom drive, ~5-10ms or more for remote drives on LAN). */
1673volume_info_data *
1674GetCachedVolumeInformation (char * root_dir)
1675{
1676 volume_info_data * info;
1677 char default_root[ MAX_PATH ];
1678
1679 /* NULL for root_dir means use root from current directory. */
1680 if (root_dir == NULL)
1681 {
1682 if (GetCurrentDirectory (MAX_PATH, default_root) == 0)
1683 return NULL;
1684 parse_root (default_root, &root_dir);
1685 *root_dir = 0;
1686 root_dir = default_root;
1687 }
1688
1689 /* Local fixed drives can be cached permanently. Removable drives
1690 cannot be cached permanently, since the volume name and serial
1691 number (if nothing else) can change. Remote drives should be
1692 treated as if they are removable, since there is no sure way to
1693 tell whether they are or not. Also, the UNC association of drive
1694 letters mapped to remote volumes can be changed at any time (even
1695 by other processes) without notice.
177c0ea7 1696
76b3903d
GV
1697 As a compromise, so we can benefit from caching info for remote
1698 volumes, we use a simple expiry mechanism to invalidate cache
1699 entries that are more than ten seconds old. */
1700
1701#if 0
1702 /* No point doing this, because WNetGetConnection is even slower than
1703 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
1704 GetDriveType is about the only call of this type which does not
1705 involve network access, and so is extremely quick). */
1706
1707 /* Map drive letter to UNC if remote. */
1708 if ( isalpha( root_dir[0] ) && !fixed[ DRIVE_INDEX( root_dir[0] ) ] )
1709 {
1710 char remote_name[ 256 ];
1711 char drive[3] = { root_dir[0], ':' };
1712
1713 if (WNetGetConnection (drive, remote_name, sizeof (remote_name))
1714 == NO_ERROR)
1715 /* do something */ ;
1716 }
1717#endif
1718
1719 info = lookup_volume_info (root_dir);
1720
1721 if (info == NULL || ! VOLINFO_STILL_VALID (root_dir, info))
1722 {
1723 char name[ 256 ];
1724 DWORD serialnum;
1725 DWORD maxcomp;
1726 DWORD flags;
1727 char type[ 256 ];
1728
1729 /* Info is not cached, or is stale. */
1730 if (!GetVolumeInformation (root_dir,
1731 name, sizeof (name),
1732 &serialnum,
1733 &maxcomp,
1734 &flags,
1735 type, sizeof (type)))
1736 return NULL;
1737
1738 /* Cache the volume information for future use, overwriting existing
1739 entry if present. */
1740 if (info == NULL)
1741 {
1742 info = (volume_info_data *) xmalloc (sizeof (volume_info_data));
1743 add_volume_info (root_dir, info);
1744 }
1745 else
1746 {
a302c7ae
AI
1747 xfree (info->name);
1748 xfree (info->type);
76b3903d
GV
1749 }
1750
a302c7ae 1751 info->name = xstrdup (name);
76b3903d
GV
1752 info->serialnum = serialnum;
1753 info->maxcomp = maxcomp;
1754 info->flags = flags;
a302c7ae 1755 info->type = xstrdup (type);
76b3903d
GV
1756 info->timestamp = GetTickCount ();
1757 }
1758
1759 return info;
1760}
480b0c5b
GV
1761
1762/* Get information on the volume where name is held; set path pointer to
1763 start of pathname in name (past UNC header\volume header if present). */
1764int
1765get_volume_info (const char * name, const char ** pPath)
95ed0025 1766{
480b0c5b
GV
1767 char temp[MAX_PATH];
1768 char *rootname = NULL; /* default to current volume */
76b3903d 1769 volume_info_data * info;
480b0c5b
GV
1770
1771 if (name == NULL)
1772 return FALSE;
1773
1774 /* find the root name of the volume if given */
1775 if (isalpha (name[0]) && name[1] == ':')
1776 {
1777 rootname = temp;
1778 temp[0] = *name++;
1779 temp[1] = *name++;
1780 temp[2] = '\\';
1781 temp[3] = 0;
1782 }
1783 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
95ed0025 1784 {
480b0c5b
GV
1785 char *str = temp;
1786 int slashes = 4;
1787 rootname = temp;
1788 do
1789 {
1790 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
1791 break;
1792 *str++ = *name++;
1793 }
1794 while ( *name );
1795
480b0c5b
GV
1796 *str++ = '\\';
1797 *str = 0;
95ed0025 1798 }
480b0c5b
GV
1799
1800 if (pPath)
1801 *pPath = name;
177c0ea7 1802
76b3903d
GV
1803 info = GetCachedVolumeInformation (rootname);
1804 if (info != NULL)
95ed0025 1805 {
76b3903d
GV
1806 /* Set global referenced by other functions. */
1807 volume_info = *info;
480b0c5b 1808 return TRUE;
95ed0025 1809 }
480b0c5b
GV
1810 return FALSE;
1811}
1812
1813/* Determine if volume is FAT format (ie. only supports short 8.3
1814 names); also set path pointer to start of pathname in name. */
1815int
1816is_fat_volume (const char * name, const char ** pPath)
1817{
1818 if (get_volume_info (name, pPath))
1819 return (volume_info.maxcomp == 12);
1820 return FALSE;
1821}
1822
4d90eee4 1823/* Map filename to a valid 8.3 name if necessary. */
480b0c5b 1824const char *
fbd6baed 1825map_w32_filename (const char * name, const char ** pPath)
480b0c5b
GV
1826{
1827 static char shortname[MAX_PATH];
1828 char * str = shortname;
1829 char c;
480b0c5b 1830 char * path;
76b3903d 1831 const char * save_name = name;
480b0c5b 1832
ca149beb
AI
1833 if (strlen (name) >= MAX_PATH)
1834 {
1835 /* Return a filename which will cause callers to fail. */
1836 strcpy (shortname, "?");
1837 return shortname;
1838 }
1839
a302c7ae 1840 if (is_fat_volume (name, (const char **)&path)) /* truncate to 8.3 */
95ed0025 1841 {
480b0c5b
GV
1842 register int left = 8; /* maximum number of chars in part */
1843 register int extn = 0; /* extension added? */
1844 register int dots = 2; /* maximum number of dots allowed */
1845
1846 while (name < path)
1847 *str++ = *name++; /* skip past UNC header */
1848
1849 while ((c = *name++))
1850 {
1851 switch ( c )
1852 {
1853 case '\\':
1854 case '/':
1855 *str++ = '\\';
1856 extn = 0; /* reset extension flags */
1857 dots = 2; /* max 2 dots */
1858 left = 8; /* max length 8 for main part */
1859 break;
1860 case ':':
1861 *str++ = ':';
1862 extn = 0; /* reset extension flags */
1863 dots = 2; /* max 2 dots */
1864 left = 8; /* max length 8 for main part */
1865 break;
1866 case '.':
1867 if ( dots )
1868 {
1869 /* Convert path components of the form .xxx to _xxx,
1870 but leave . and .. as they are. This allows .emacs
1871 to be read as _emacs, for example. */
1872
1873 if (! *name ||
1874 *name == '.' ||
1875 IS_DIRECTORY_SEP (*name))
1876 {
1877 *str++ = '.';
1878 dots--;
1879 }
1880 else
1881 {
1882 *str++ = '_';
1883 left--;
1884 dots = 0;
1885 }
1886 }
1887 else if ( !extn )
1888 {
1889 *str++ = '.';
1890 extn = 1; /* we've got an extension */
1891 left = 3; /* 3 chars in extension */
1892 }
1893 else
1894 {
1895 /* any embedded dots after the first are converted to _ */
1896 *str++ = '_';
1897 }
1898 break;
1899 case '~':
1900 case '#': /* don't lose these, they're important */
1901 if ( ! left )
1902 str[-1] = c; /* replace last character of part */
1903 /* FALLTHRU */
1904 default:
1905 if ( left )
1906 {
1907 *str++ = tolower (c); /* map to lower case (looks nicer) */
1908 left--;
1909 dots = 0; /* started a path component */
1910 }
1911 break;
1912 }
1913 }
1914 *str = '\0';
fc85cb29
RS
1915 }
1916 else
1917 {
1918 strcpy (shortname, name);
1919 unixtodos_filename (shortname);
95ed0025 1920 }
480b0c5b
GV
1921
1922 if (pPath)
76b3903d 1923 *pPath = shortname + (path - save_name);
480b0c5b 1924
fc85cb29 1925 return shortname;
480b0c5b
GV
1926}
1927
b3308d2e
KH
1928static int
1929is_exec (const char * name)
1930{
1931 char * p = strrchr (name, '.');
1932 return
1933 (p != NULL
05131107
JR
1934 && (xstrcasecmp (p, ".exe") == 0 ||
1935 xstrcasecmp (p, ".com") == 0 ||
1936 xstrcasecmp (p, ".bat") == 0 ||
1937 xstrcasecmp (p, ".cmd") == 0));
b3308d2e
KH
1938}
1939
177c0ea7 1940/* Emulate the Unix directory procedures opendir, closedir,
76b3903d
GV
1941 and readdir. We can't use the procedures supplied in sysdep.c,
1942 so we provide them here. */
1943
1944struct direct dir_static; /* simulated directory contents */
1945static HANDLE dir_find_handle = INVALID_HANDLE_VALUE;
1946static int dir_is_fat;
1947static char dir_pathname[MAXPATHLEN+1];
1948static WIN32_FIND_DATA dir_find_data;
1949
9d3355d1
GV
1950/* Support shares on a network resource as subdirectories of a read-only
1951 root directory. */
1952static HANDLE wnet_enum_handle = INVALID_HANDLE_VALUE;
e0c181dd 1953HANDLE open_unc_volume (const char *);
9d3355d1
GV
1954char *read_unc_volume (HANDLE, char *, int);
1955void close_unc_volume (HANDLE);
1956
76b3903d
GV
1957DIR *
1958opendir (char *filename)
1959{
1960 DIR *dirp;
1961
1962 /* Opening is done by FindFirstFile. However, a read is inherent to
1963 this operation, so we defer the open until read time. */
1964
76b3903d
GV
1965 if (dir_find_handle != INVALID_HANDLE_VALUE)
1966 return NULL;
9d3355d1
GV
1967 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
1968 return NULL;
1969
1970 if (is_unc_volume (filename))
1971 {
1972 wnet_enum_handle = open_unc_volume (filename);
1973 if (wnet_enum_handle == INVALID_HANDLE_VALUE)
1974 return NULL;
1975 }
1976
1977 if (!(dirp = (DIR *) malloc (sizeof (DIR))))
1978 return NULL;
76b3903d
GV
1979
1980 dirp->dd_fd = 0;
1981 dirp->dd_loc = 0;
1982 dirp->dd_size = 0;
1983
1984 strncpy (dir_pathname, map_w32_filename (filename, NULL), MAXPATHLEN);
1985 dir_pathname[MAXPATHLEN] = '\0';
1986 dir_is_fat = is_fat_volume (filename, NULL);
1987
1988 return dirp;
1989}
1990
1991void
1992closedir (DIR *dirp)
1993{
1994 /* If we have a find-handle open, close it. */
1995 if (dir_find_handle != INVALID_HANDLE_VALUE)
1996 {
1997 FindClose (dir_find_handle);
1998 dir_find_handle = INVALID_HANDLE_VALUE;
1999 }
9d3355d1
GV
2000 else if (wnet_enum_handle != INVALID_HANDLE_VALUE)
2001 {
2002 close_unc_volume (wnet_enum_handle);
2003 wnet_enum_handle = INVALID_HANDLE_VALUE;
2004 }
76b3903d
GV
2005 xfree ((char *) dirp);
2006}
2007
2008struct direct *
2009readdir (DIR *dirp)
2010{
b07103dc
EZ
2011 int downcase = !NILP (Vw32_downcase_file_names);
2012
9d3355d1
GV
2013 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
2014 {
177c0ea7
JB
2015 if (!read_unc_volume (wnet_enum_handle,
2016 dir_find_data.cFileName,
9d3355d1
GV
2017 MAX_PATH))
2018 return NULL;
2019 }
76b3903d 2020 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
9d3355d1 2021 else if (dir_find_handle == INVALID_HANDLE_VALUE)
76b3903d
GV
2022 {
2023 char filename[MAXNAMLEN + 3];
2024 int ln;
2025
2026 strcpy (filename, dir_pathname);
2027 ln = strlen (filename) - 1;
2028 if (!IS_DIRECTORY_SEP (filename[ln]))
2029 strcat (filename, "\\");
2030 strcat (filename, "*");
2031
2032 dir_find_handle = FindFirstFile (filename, &dir_find_data);
2033
2034 if (dir_find_handle == INVALID_HANDLE_VALUE)
2035 return NULL;
2036 }
2037 else
2038 {
2039 if (!FindNextFile (dir_find_handle, &dir_find_data))
2040 return NULL;
2041 }
177c0ea7 2042
76b3903d
GV
2043 /* Emacs never uses this value, so don't bother making it match
2044 value returned by stat(). */
2045 dir_static.d_ino = 1;
177c0ea7 2046
b07103dc
EZ
2047 strcpy (dir_static.d_name, dir_find_data.cFileName);
2048
2049 /* If the file name in cFileName[] includes `?' characters, it means
2050 the original file name used characters that cannot be represented
2051 by the current ANSI codepage. To avoid total lossage, retrieve
2052 the short 8+3 alias of the long file name. */
2053 if (_mbspbrk (dir_static.d_name, "?"))
2054 {
2055 strcpy (dir_static.d_name, dir_find_data.cAlternateFileName);
2056 downcase = 1; /* 8+3 aliases are returned in all caps */
2057 }
2058 dir_static.d_namlen = strlen (dir_static.d_name);
76b3903d
GV
2059 dir_static.d_reclen = sizeof (struct direct) - MAXNAMLEN + 3 +
2060 dir_static.d_namlen - dir_static.d_namlen % 4;
177c0ea7 2061
192788d7
EZ
2062 /* If the file name in cFileName[] includes `?' characters, it means
2063 the original file name used characters that cannot be represented
2064 by the current ANSI codepage. To avoid total lossage, retrieve
2065 the short 8+3 alias of the long file name. */
2066 if (_mbspbrk (dir_find_data.cFileName, "?"))
2067 {
2068 strcpy (dir_static.d_name, dir_find_data.cAlternateFileName);
2069 /* 8+3 aliases are returned in all caps, which could break
2070 various alists that look at filenames' extensions. */
2071 downcase = 1;
2072 }
2073 else
2074 strcpy (dir_static.d_name, dir_find_data.cFileName);
2075 dir_static.d_namlen = strlen (dir_static.d_name);
76b3903d
GV
2076 if (dir_is_fat)
2077 _strlwr (dir_static.d_name);
b07103dc 2078 else if (downcase)
76b3903d
GV
2079 {
2080 register char *p;
2081 for (p = dir_static.d_name; *p; p++)
2082 if (*p >= 'a' && *p <= 'z')
2083 break;
2084 if (!*p)
2085 _strlwr (dir_static.d_name);
2086 }
177c0ea7 2087
76b3903d
GV
2088 return &dir_static;
2089}
2090
9d3355d1 2091HANDLE
e0c181dd 2092open_unc_volume (const char *path)
9d3355d1 2093{
177c0ea7 2094 NETRESOURCE nr;
9d3355d1
GV
2095 HANDLE henum;
2096 int result;
2097
177c0ea7
JB
2098 nr.dwScope = RESOURCE_GLOBALNET;
2099 nr.dwType = RESOURCETYPE_DISK;
2100 nr.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
2101 nr.dwUsage = RESOURCEUSAGE_CONTAINER;
2102 nr.lpLocalName = NULL;
6e602566 2103 nr.lpRemoteName = (LPSTR)map_w32_filename (path, NULL);
177c0ea7
JB
2104 nr.lpComment = NULL;
2105 nr.lpProvider = NULL;
9d3355d1 2106
177c0ea7 2107 result = WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
9d3355d1
GV
2108 RESOURCEUSAGE_CONNECTABLE, &nr, &henum);
2109
2110 if (result == NO_ERROR)
2111 return henum;
2112 else
2113 return INVALID_HANDLE_VALUE;
2114}
2115
2116char *
2117read_unc_volume (HANDLE henum, char *readbuf, int size)
2118{
a302c7ae 2119 DWORD count;
9d3355d1 2120 int result;
a302c7ae 2121 DWORD bufsize = 512;
9d3355d1
GV
2122 char *buffer;
2123 char *ptr;
2124
2125 count = 1;
2126 buffer = alloca (bufsize);
2127 result = WNetEnumResource (wnet_enum_handle, &count, buffer, &bufsize);
2128 if (result != NO_ERROR)
2129 return NULL;
2130
2131 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
2132 ptr = ((LPNETRESOURCE) buffer)->lpRemoteName;
2133 ptr += 2;
2134 while (*ptr && !IS_DIRECTORY_SEP (*ptr)) ptr++;
2135 ptr++;
2136
2137 strncpy (readbuf, ptr, size);
2138 return readbuf;
2139}
2140
2141void
2142close_unc_volume (HANDLE henum)
2143{
2144 if (henum != INVALID_HANDLE_VALUE)
2145 WNetCloseEnum (henum);
2146}
2147
2148DWORD
e0c181dd 2149unc_volume_file_attributes (const char *path)
9d3355d1
GV
2150{
2151 HANDLE henum;
2152 DWORD attrs;
2153
2154 henum = open_unc_volume (path);
2155 if (henum == INVALID_HANDLE_VALUE)
2156 return -1;
2157
2158 attrs = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY;
2159
2160 close_unc_volume (henum);
2161
2162 return attrs;
2163}
2164
302d7d54
JR
2165/* Ensure a network connection is authenticated. */
2166static void
2167logon_network_drive (const char *path)
2168{
2169 NETRESOURCE resource;
2170 char share[MAX_PATH];
2171 int i, n_slashes;
40a339c8
JR
2172 char drive[4];
2173
2174 sprintf (drive, "%c:\\", path[0]);
302d7d54
JR
2175
2176 /* Only logon to networked drives. */
40a339c8
JR
2177 if ((!IS_DIRECTORY_SEP (path[0]) || !IS_DIRECTORY_SEP (path[1]))
2178 && GetDriveType (drive) != DRIVE_REMOTE)
302d7d54 2179 return;
40a339c8 2180
302d7d54
JR
2181 n_slashes = 2;
2182 strncpy (share, path, MAX_PATH);
2183 /* Truncate to just server and share name. */
2184 for (i = 2; i < MAX_PATH; i++)
2185 {
2186 if (IS_DIRECTORY_SEP (share[i]) && ++n_slashes > 3)
2187 {
2188 share[i] = '\0';
2189 break;
2190 }
2191 }
2192
2193 resource.dwType = RESOURCETYPE_DISK;
2194 resource.lpLocalName = NULL;
2195 resource.lpRemoteName = share;
2196 resource.lpProvider = NULL;
2197
2198 WNetAddConnection2 (&resource, NULL, NULL, CONNECT_INTERACTIVE);
2199}
480b0c5b
GV
2200
2201/* Shadow some MSVC runtime functions to map requests for long filenames
2202 to reasonable short names if necessary. This was originally added to
177c0ea7 2203 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
480b0c5b
GV
2204 long file names. */
2205
2206int
2207sys_access (const char * path, int mode)
2208{
b3308d2e
KH
2209 DWORD attributes;
2210
2211 /* MSVC implementation doesn't recognize D_OK. */
2212 path = map_w32_filename (path, NULL);
9d3355d1
GV
2213 if (is_unc_volume (path))
2214 {
2215 attributes = unc_volume_file_attributes (path);
2216 if (attributes == -1) {
2217 errno = EACCES;
2218 return -1;
2219 }
2220 }
2221 else if ((attributes = GetFileAttributes (path)) == -1)
b3308d2e
KH
2222 {
2223 /* Should try mapping GetLastError to errno; for now just indicate
2224 that path doesn't exist. */
2225 errno = EACCES;
2226 return -1;
2227 }
2228 if ((mode & X_OK) != 0 && !is_exec (path))
2229 {
2230 errno = EACCES;
2231 return -1;
2232 }
2233 if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0)
2234 {
2235 errno = EACCES;
2236 return -1;
2237 }
2238 if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
2239 {
2240 errno = EACCES;
2241 return -1;
2242 }
2243 return 0;
480b0c5b
GV
2244}
2245
2246int
2247sys_chdir (const char * path)
2248{
fbd6baed 2249 return _chdir (map_w32_filename (path, NULL));
480b0c5b
GV
2250}
2251
2252int
2253sys_chmod (const char * path, int mode)
2254{
fbd6baed 2255 return _chmod (map_w32_filename (path, NULL), mode);
480b0c5b
GV
2256}
2257
2d5ab4bf
EZ
2258int
2259sys_chown (const char *path, uid_t owner, gid_t group)
2260{
e3b88685 2261 if (sys_chmod (path, S_IREAD) == -1) /* check if file exists */
2d5ab4bf
EZ
2262 return -1;
2263 return 0;
2264}
2265
480b0c5b
GV
2266int
2267sys_creat (const char * path, int mode)
2268{
fbd6baed 2269 return _creat (map_w32_filename (path, NULL), mode);
480b0c5b
GV
2270}
2271
2272FILE *
2273sys_fopen(const char * path, const char * mode)
2274{
2275 int fd;
2276 int oflag;
2277 const char * mode_save = mode;
2278
2279 /* Force all file handles to be non-inheritable. This is necessary to
2280 ensure child processes don't unwittingly inherit handles that might
2281 prevent future file access. */
2282
2283 if (mode[0] == 'r')
2284 oflag = O_RDONLY;
2285 else if (mode[0] == 'w' || mode[0] == 'a')
2286 oflag = O_WRONLY | O_CREAT | O_TRUNC;
95ed0025 2287 else
480b0c5b
GV
2288 return NULL;
2289
2290 /* Only do simplistic option parsing. */
2291 while (*++mode)
2292 if (mode[0] == '+')
2293 {
2294 oflag &= ~(O_RDONLY | O_WRONLY);
2295 oflag |= O_RDWR;
2296 }
2297 else if (mode[0] == 'b')
2298 {
2299 oflag &= ~O_TEXT;
2300 oflag |= O_BINARY;
2301 }
2302 else if (mode[0] == 't')
2303 {
2304 oflag &= ~O_BINARY;
2305 oflag |= O_TEXT;
2306 }
2307 else break;
2308
fbd6baed 2309 fd = _open (map_w32_filename (path, NULL), oflag | _O_NOINHERIT, 0644);
480b0c5b
GV
2310 if (fd < 0)
2311 return NULL;
2312
76b3903d 2313 return _fdopen (fd, mode_save);
95ed0025 2314}
480b0c5b 2315
76b3903d 2316/* This only works on NTFS volumes, but is useful to have. */
480b0c5b 2317int
76b3903d 2318sys_link (const char * old, const char * new)
480b0c5b 2319{
76b3903d
GV
2320 HANDLE fileh;
2321 int result = -1;
2322 char oldname[MAX_PATH], newname[MAX_PATH];
2323
2324 if (old == NULL || new == NULL)
2325 {
2326 errno = ENOENT;
2327 return -1;
2328 }
2329
2330 strcpy (oldname, map_w32_filename (old, NULL));
2331 strcpy (newname, map_w32_filename (new, NULL));
2332
2333 fileh = CreateFile (oldname, 0, 0, NULL, OPEN_EXISTING,
2334 FILE_FLAG_BACKUP_SEMANTICS, NULL);
2335 if (fileh != INVALID_HANDLE_VALUE)
2336 {
2337 int wlen;
2338
2339 /* Confusingly, the "alternate" stream name field does not apply
2340 when restoring a hard link, and instead contains the actual
2341 stream data for the link (ie. the name of the link to create).
2342 The WIN32_STREAM_ID structure before the cStreamName field is
2343 the stream header, which is then immediately followed by the
2344 stream data. */
2345
2346 struct {
2347 WIN32_STREAM_ID wid;
2348 WCHAR wbuffer[MAX_PATH]; /* extra space for link name */
2349 } data;
2350
2351 wlen = MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, newname, -1,
2352 data.wid.cStreamName, MAX_PATH);
2353 if (wlen > 0)
2354 {
2355 LPVOID context = NULL;
2356 DWORD wbytes = 0;
2357
2358 data.wid.dwStreamId = BACKUP_LINK;
2359 data.wid.dwStreamAttributes = 0;
2360 data.wid.Size.LowPart = wlen * sizeof(WCHAR);
2361 data.wid.Size.HighPart = 0;
2362 data.wid.dwStreamNameSize = 0;
2363
2364 if (BackupWrite (fileh, (LPBYTE)&data,
2365 offsetof (WIN32_STREAM_ID, cStreamName)
2366 + data.wid.Size.LowPart,
2367 &wbytes, FALSE, FALSE, &context)
2368 && BackupWrite (fileh, NULL, 0, &wbytes, TRUE, FALSE, &context))
2369 {
2370 /* succeeded */
2371 result = 0;
2372 }
2373 else
2374 {
2375 /* Should try mapping GetLastError to errno; for now just
2376 indicate a general error (eg. links not supported). */
2377 errno = EINVAL; // perhaps EMLINK?
2378 }
2379 }
2380
2381 CloseHandle (fileh);
2382 }
2383 else
2384 errno = ENOENT;
2385
2386 return result;
480b0c5b
GV
2387}
2388
2389int
2390sys_mkdir (const char * path)
2391{
fbd6baed 2392 return _mkdir (map_w32_filename (path, NULL));
480b0c5b
GV
2393}
2394
9d1778b1
RS
2395/* Because of long name mapping issues, we need to implement this
2396 ourselves. Also, MSVC's _mktemp returns NULL when it can't generate
2397 a unique name, instead of setting the input template to an empty
2398 string.
2399
2400 Standard algorithm seems to be use pid or tid with a letter on the
2401 front (in place of the 6 X's) and cycle through the letters to find a
2402 unique name. We extend that to allow any reasonable character as the
2403 first of the 6 X's. */
480b0c5b
GV
2404char *
2405sys_mktemp (char * template)
2406{
9d1778b1
RS
2407 char * p;
2408 int i;
2409 unsigned uid = GetCurrentThreadId ();
2410 static char first_char[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
2411
2412 if (template == NULL)
2413 return NULL;
2414 p = template + strlen (template);
2415 i = 5;
2416 /* replace up to the last 5 X's with uid in decimal */
2417 while (--p >= template && p[0] == 'X' && --i >= 0)
2418 {
2419 p[0] = '0' + uid % 10;
2420 uid /= 10;
2421 }
2422
2423 if (i < 0 && p[0] == 'X')
2424 {
2425 i = 0;
2426 do
2427 {
2428 int save_errno = errno;
2429 p[0] = first_char[i];
2430 if (sys_access (template, 0) < 0)
2431 {
2432 errno = save_errno;
2433 return template;
2434 }
2435 }
2436 while (++i < sizeof (first_char));
2437 }
2438
2439 /* Template is badly formed or else we can't generate a unique name,
2440 so return empty string */
2441 template[0] = 0;
2442 return template;
480b0c5b
GV
2443}
2444
2445int
2446sys_open (const char * path, int oflag, int mode)
2447{
302f0b29
GM
2448 const char* mpath = map_w32_filename (path, NULL);
2449 /* Try to open file without _O_CREAT, to be able to write to hidden
2450 and system files. Force all file handles to be
2451 non-inheritable. */
2452 int res = _open (mpath, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
2453 if (res >= 0)
2454 return res;
2455 return _open (mpath, oflag | _O_NOINHERIT, mode);
480b0c5b
GV
2456}
2457
2458int
2459sys_rename (const char * oldname, const char * newname)
2460{
cfb5e855 2461 BOOL result;
b3308d2e 2462 char temp[MAX_PATH];
480b0c5b 2463
e9e23e23 2464 /* MoveFile on Windows 95 doesn't correctly change the short file name
5162ffce
MB
2465 alias in a number of circumstances (it is not easy to predict when
2466 just by looking at oldname and newname, unfortunately). In these
2467 cases, renaming through a temporary name avoids the problem.
2468
e9e23e23 2469 A second problem on Windows 95 is that renaming through a temp name when
5162ffce
MB
2470 newname is uppercase fails (the final long name ends up in
2471 lowercase, although the short alias might be uppercase) UNLESS the
2472 long temp name is not 8.3.
2473
e9e23e23 2474 So, on Windows 95 we always rename through a temp name, and we make sure
5162ffce 2475 the temp name has a long extension to ensure correct renaming. */
480b0c5b 2476
fbd6baed 2477 strcpy (temp, map_w32_filename (oldname, NULL));
480b0c5b 2478
76b3903d 2479 if (os_subtype == OS_WIN95)
480b0c5b 2480 {
b3308d2e 2481 char * o;
480b0c5b 2482 char * p;
b3308d2e
KH
2483 int i = 0;
2484
2485 oldname = map_w32_filename (oldname, NULL);
2486 if (o = strrchr (oldname, '\\'))
2487 o++;
2488 else
2489 o = (char *) oldname;
480b0c5b 2490
480b0c5b
GV
2491 if (p = strrchr (temp, '\\'))
2492 p++;
2493 else
2494 p = temp;
b3308d2e
KH
2495
2496 do
2497 {
2498 /* Force temp name to require a manufactured 8.3 alias - this
2499 seems to make the second rename work properly. */
f313ee82 2500 sprintf (p, "_.%s.%u", o, i);
b3308d2e 2501 i++;
58f0cb7e 2502 result = rename (oldname, temp);
b3308d2e
KH
2503 }
2504 /* This loop must surely terminate! */
cfb5e855 2505 while (result < 0 && errno == EEXIST);
58f0cb7e 2506 if (result < 0)
480b0c5b
GV
2507 return -1;
2508 }
2509
2510 /* Emulate Unix behaviour - newname is deleted if it already exists
5162ffce 2511 (at least if it is a file; don't do this for directories).
76b3903d 2512
b3308d2e
KH
2513 Since we mustn't do this if we are just changing the case of the
2514 file name (we would end up deleting the file we are trying to
2515 rename!), we let rename detect if the destination file already
2516 exists - that way we avoid the possible pitfalls of trying to
2517 determine ourselves whether two names really refer to the same
2518 file, which is not always possible in the general case. (Consider
2519 all the permutations of shared or subst'd drives, etc.) */
2520
2521 newname = map_w32_filename (newname, NULL);
eb9ea53f 2522 result = rename (temp, newname);
b3308d2e
KH
2523
2524 if (result < 0
cfb5e855 2525 && errno == EEXIST
b3308d2e
KH
2526 && _chmod (newname, 0666) == 0
2527 && _unlink (newname) == 0)
2528 result = rename (temp, newname);
480b0c5b 2529
eb9ea53f 2530 return result;
480b0c5b
GV
2531}
2532
2533int
2534sys_rmdir (const char * path)
2535{
fbd6baed 2536 return _rmdir (map_w32_filename (path, NULL));
480b0c5b
GV
2537}
2538
2539int
2540sys_unlink (const char * path)
2541{
16bb7578
GV
2542 path = map_w32_filename (path, NULL);
2543
2544 /* On Unix, unlink works without write permission. */
2545 _chmod (path, 0666);
2546 return _unlink (path);
480b0c5b
GV
2547}
2548
2549static FILETIME utc_base_ft;
2550static long double utc_base;
2551static int init = 0;
2552
2553static time_t
2554convert_time (FILETIME ft)
2555{
2556 long double ret;
2557
2558 if (!init)
2559 {
2560 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
2561 SYSTEMTIME st;
2562
2563 st.wYear = 1970;
2564 st.wMonth = 1;
2565 st.wDay = 1;
2566 st.wHour = 0;
2567 st.wMinute = 0;
2568 st.wSecond = 0;
2569 st.wMilliseconds = 0;
2570
2571 SystemTimeToFileTime (&st, &utc_base_ft);
2572 utc_base = (long double) utc_base_ft.dwHighDateTime
69b72317 2573 * 4096.0L * 1024.0L * 1024.0L + utc_base_ft.dwLowDateTime;
480b0c5b
GV
2574 init = 1;
2575 }
2576
2577 if (CompareFileTime (&ft, &utc_base_ft) < 0)
2578 return 0;
2579
69b72317
EZ
2580 ret = (long double) ft.dwHighDateTime
2581 * 4096.0L * 1024.0L * 1024.0L + ft.dwLowDateTime;
480b0c5b 2582 ret -= utc_base;
69b72317 2583 return (time_t) (ret * 1e-7L);
480b0c5b
GV
2584}
2585
480b0c5b
GV
2586void
2587convert_from_time_t (time_t time, FILETIME * pft)
2588{
2589 long double tmp;
2590
2591 if (!init)
2592 {
2593 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
2594 SYSTEMTIME st;
2595
2596 st.wYear = 1970;
2597 st.wMonth = 1;
2598 st.wDay = 1;
2599 st.wHour = 0;
2600 st.wMinute = 0;
2601 st.wSecond = 0;
2602 st.wMilliseconds = 0;
2603
2604 SystemTimeToFileTime (&st, &utc_base_ft);
2605 utc_base = (long double) utc_base_ft.dwHighDateTime
2606 * 4096 * 1024 * 1024 + utc_base_ft.dwLowDateTime;
2607 init = 1;
2608 }
2609
2610 /* time in 100ns units since 1-Jan-1601 */
2611 tmp = (long double) time * 1e7 + utc_base;
2612 pft->dwHighDateTime = (DWORD) (tmp / (4096.0 * 1024 * 1024));
16bb7578 2613 pft->dwLowDateTime = (DWORD) (tmp - (4096.0 * 1024 * 1024) * pft->dwHighDateTime);
480b0c5b 2614}
480b0c5b 2615
76b3903d
GV
2616#if 0
2617/* No reason to keep this; faking inode values either by hashing or even
2618 using the file index from GetInformationByHandle, is not perfect and
2619 so by default Emacs doesn't use the inode values on Windows.
2620 Instead, we now determine file-truename correctly (except for
2621 possible drive aliasing etc). */
2622
2623/* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
480b0c5b 2624static unsigned
76b3903d 2625hashval (const unsigned char * str)
480b0c5b
GV
2626{
2627 unsigned h = 0;
480b0c5b
GV
2628 while (*str)
2629 {
2630 h = (h << 4) + *str++;
76b3903d 2631 h ^= (h >> 28);
480b0c5b
GV
2632 }
2633 return h;
2634}
2635
2636/* Return the hash value of the canonical pathname, excluding the
2637 drive/UNC header, to get a hopefully unique inode number. */
76b3903d 2638static DWORD
480b0c5b
GV
2639generate_inode_val (const char * name)
2640{
2641 char fullname[ MAX_PATH ];
2642 char * p;
2643 unsigned hash;
2644
76b3903d
GV
2645 /* Get the truly canonical filename, if it exists. (Note: this
2646 doesn't resolve aliasing due to subst commands, or recognise hard
2647 links. */
2648 if (!w32_get_long_filename ((char *)name, fullname, MAX_PATH))
2649 abort ();
2650
2651 parse_root (fullname, &p);
fbd6baed 2652 /* Normal W32 filesystems are still case insensitive. */
480b0c5b 2653 _strlwr (p);
76b3903d 2654 return hashval (p);
480b0c5b
GV
2655}
2656
76b3903d
GV
2657#endif
2658
8aaaec6b
EZ
2659static PSECURITY_DESCRIPTOR
2660get_file_security_desc (const char *fname)
2661{
2662 PSECURITY_DESCRIPTOR psd = NULL;
2663 DWORD sd_len, err;
2664 SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION
2665 | GROUP_SECURITY_INFORMATION /* | DACL_SECURITY_INFORMATION */ ;
2666
2667 if (!get_file_security (fname, si, psd, 0, &sd_len))
2668 {
2669 err = GetLastError ();
2670 if (err != ERROR_INSUFFICIENT_BUFFER)
2671 return NULL;
2672 }
2673
2674 psd = xmalloc (sd_len);
2675 if (!get_file_security (fname, si, psd, sd_len, &sd_len))
2676 {
2677 xfree (psd);
2678 return NULL;
2679 }
2680
2681 return psd;
2682}
2683
2684static DWORD
2685get_rid (PSID sid)
2686{
2687 unsigned n_subauthorities;
2688
2689 /* Use the last sub-authority value of the RID, the relative
2690 portion of the SID, as user/group ID. */
2691 n_subauthorities = *get_sid_sub_authority_count (sid);
2692 if (n_subauthorities < 1)
2693 return 0; /* the "World" RID */
2694 return *get_sid_sub_authority (sid, n_subauthorities - 1);
2695}
2696
2697#define UID 1
2698#define GID 2
2699
2700static int
2701get_name_and_id (PSECURITY_DESCRIPTOR psd, const char *fname,
2702 int *id, char *nm, int what)
2703{
2704 PSID sid = NULL;
2705 char machine[MAX_COMPUTERNAME_LENGTH+1];
2706 BOOL dflt;
2707 SID_NAME_USE ignore;
2708 char name[UNLEN+1];
2709 DWORD name_len = sizeof (name);
2710 char domain[1024];
2711 DWORD domain_len = sizeof(domain);
2712 char *mp = NULL;
2713 int use_dflt = 0;
2714 int result;
2715
2716 if (what == UID)
2717 result = get_security_descriptor_owner (psd, &sid, &dflt);
2718 else if (what == GID)
2719 result = get_security_descriptor_group (psd, &sid, &dflt);
2720 else
2721 result = 0;
2722
2723 if (!result || !is_valid_sid (sid))
2724 use_dflt = 1;
2725 else
2726 {
2727 /* If FNAME is a UNC, we need to lookup account on the
2728 specified machine. */
2729 if (IS_DIRECTORY_SEP (fname[0]) && IS_DIRECTORY_SEP (fname[1])
2730 && fname[2] != '\0')
2731 {
2732 const char *s;
2733 char *p;
2734
2735 for (s = fname + 2, p = machine;
2736 *s && !IS_DIRECTORY_SEP (*s); s++, p++)
2737 *p = *s;
2738 *p = '\0';
2739 mp = machine;
2740 }
2741
2742 if (!lookup_account_sid (mp, sid, name, &name_len,
2743 domain, &domain_len, &ignore)
2744 || name_len > UNLEN+1)
2745 use_dflt = 1;
2746 else
2747 {
2748 *id = get_rid (sid);
2749 strcpy (nm, name);
2750 }
2751 }
2752 return use_dflt;
2753}
2754
2755static void
2756get_file_owner_and_group (
2757 PSECURITY_DESCRIPTOR psd,
2758 const char *fname,
2759 struct stat *st)
2760{
2761 int dflt_usr = 0, dflt_grp = 0;
2762
2763 if (!psd)
2764 {
2765 dflt_usr = 1;
2766 dflt_grp = 1;
2767 }
2768 else
2769 {
2770 if (get_name_and_id (psd, fname, &st->st_uid, st->st_uname, UID))
2771 dflt_usr = 1;
2772 if (get_name_and_id (psd, fname, &st->st_gid, st->st_gname, GID))
2773 dflt_grp = 1;
2774 }
2775 /* Consider files to belong to current user/group, if we cannot get
2776 more accurate information. */
2777 if (dflt_usr)
2778 {
2779 st->st_uid = dflt_passwd.pw_uid;
2780 strcpy (st->st_uname, dflt_passwd.pw_name);
2781 }
2782 if (dflt_grp)
2783 {
2784 st->st_gid = dflt_passwd.pw_gid;
2785 strcpy (st->st_gname, dflt_group.gr_name);
2786 }
2787}
2788
480b0c5b
GV
2789/* MSVC stat function can't cope with UNC names and has other bugs, so
2790 replace it with our own. This also allows us to calculate consistent
2791 inode values without hacks in the main Emacs code. */
2792int
2793stat (const char * path, struct stat * buf)
2794{
eb9ea53f 2795 char *name, *r;
480b0c5b
GV
2796 WIN32_FIND_DATA wfd;
2797 HANDLE fh;
e3b88685 2798 unsigned __int64 fake_inode;
480b0c5b
GV
2799 int permission;
2800 int len;
2801 int rootdir = FALSE;
8aaaec6b 2802 PSECURITY_DESCRIPTOR psd = NULL;
480b0c5b
GV
2803
2804 if (path == NULL || buf == NULL)
2805 {
2806 errno = EFAULT;
2807 return -1;
2808 }
2809
fbd6baed 2810 name = (char *) map_w32_filename (path, &path);
22189f79
EZ
2811 /* Must be valid filename, no wild cards or other invalid
2812 characters. We use _mbspbrk to support multibyte strings that
2813 might look to strpbrk as if they included literal *, ?, and other
2814 characters mentioned below that are disallowed by Windows
2815 filesystems. */
2816 if (_mbspbrk (name, "*?|<>\""))
480b0c5b
GV
2817 {
2818 errno = ENOENT;
2819 return -1;
2820 }
2821
eb9ea53f
GV
2822 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
2823 r = IS_DEVICE_SEP (name[1]) ? &name[2] : name;
2824 if (IS_DIRECTORY_SEP (r[0]) && r[1] == '.' && r[2] == '.' && r[3] == '\0')
2825 {
2826 r[1] = r[2] = '\0';
2827 }
2828
480b0c5b
GV
2829 /* Remove trailing directory separator, unless name is the root
2830 directory of a drive or UNC volume in which case ensure there
2831 is a trailing separator. */
2832 len = strlen (name);
2833 rootdir = (path >= name + len - 1
2834 && (IS_DIRECTORY_SEP (*path) || *path == 0));
2835 name = strcpy (alloca (len + 2), name);
2836
9d3355d1
GV
2837 if (is_unc_volume (name))
2838 {
2839 DWORD attrs = unc_volume_file_attributes (name);
2840
2841 if (attrs == -1)
2842 return -1;
2843
2844 memset (&wfd, 0, sizeof (wfd));
2845 wfd.dwFileAttributes = attrs;
2846 wfd.ftCreationTime = utc_base_ft;
2847 wfd.ftLastAccessTime = utc_base_ft;
2848 wfd.ftLastWriteTime = utc_base_ft;
2849 strcpy (wfd.cFileName, name);
2850 }
2851 else if (rootdir)
480b0c5b
GV
2852 {
2853 if (!IS_DIRECTORY_SEP (name[len-1]))
2854 strcat (name, "\\");
2855 if (GetDriveType (name) < 2)
2856 {
2857 errno = ENOENT;
2858 return -1;
2859 }
2860 memset (&wfd, 0, sizeof (wfd));
2861 wfd.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
2862 wfd.ftCreationTime = utc_base_ft;
2863 wfd.ftLastAccessTime = utc_base_ft;
2864 wfd.ftLastWriteTime = utc_base_ft;
2865 strcpy (wfd.cFileName, name);
2866 }
2867 else
2868 {
2869 if (IS_DIRECTORY_SEP (name[len-1]))
2870 name[len - 1] = 0;
76b3903d
GV
2871
2872 /* (This is hacky, but helps when doing file completions on
2873 network drives.) Optimize by using information available from
2874 active readdir if possible. */
b19cc00c
GV
2875 len = strlen (dir_pathname);
2876 if (IS_DIRECTORY_SEP (dir_pathname[len-1]))
2877 len--;
76b3903d 2878 if (dir_find_handle != INVALID_HANDLE_VALUE
b19cc00c 2879 && strnicmp (name, dir_pathname, len) == 0
76b3903d 2880 && IS_DIRECTORY_SEP (name[len])
05131107 2881 && xstrcasecmp (name + len + 1, dir_static.d_name) == 0)
480b0c5b 2882 {
76b3903d
GV
2883 /* This was the last entry returned by readdir. */
2884 wfd = dir_find_data;
2885 }
2886 else
2887 {
513feaa5 2888 logon_network_drive (name);
302d7d54 2889
76b3903d
GV
2890 fh = FindFirstFile (name, &wfd);
2891 if (fh == INVALID_HANDLE_VALUE)
2892 {
2893 errno = ENOENT;
2894 return -1;
2895 }
2896 FindClose (fh);
480b0c5b 2897 }
480b0c5b
GV
2898 }
2899
8aaaec6b
EZ
2900 if (!(NILP (Vw32_get_true_file_attributes)
2901 || (EQ (Vw32_get_true_file_attributes, Qlocal) &&
2a85f0c2 2902 GetDriveType (name) != DRIVE_FIXED))
93e0f0da
JR
2903 /* No access rights required to get info. */
2904 && (fh = CreateFile (name, 0, 0, NULL, OPEN_EXISTING,
2905 FILE_FLAG_BACKUP_SEMANTICS, NULL))
2906 != INVALID_HANDLE_VALUE)
480b0c5b 2907 {
480b0c5b 2908 /* This is more accurate in terms of gettting the correct number
aa5ee2a3 2909 of links, but is quite slow (it is noticeable when Emacs is
480b0c5b
GV
2910 making a list of file name completions). */
2911 BY_HANDLE_FILE_INFORMATION info;
2912
480b0c5b
GV
2913 if (GetFileInformationByHandle (fh, &info))
2914 {
480b0c5b 2915 buf->st_nlink = info.nNumberOfLinks;
76b3903d
GV
2916 /* Might as well use file index to fake inode values, but this
2917 is not guaranteed to be unique unless we keep a handle open
2918 all the time (even then there are situations where it is
2919 not unique). Reputedly, there are at most 48 bits of info
2920 (on NTFS, presumably less on FAT). */
e3b88685
EZ
2921 fake_inode = info.nFileIndexHigh;
2922 fake_inode <<= 32;
2923 fake_inode += info.nFileIndexLow;
480b0c5b
GV
2924 }
2925 else
2926 {
01f31dfb
AI
2927 buf->st_nlink = 1;
2928 fake_inode = 0;
2929 }
2930
93e0f0da 2931 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
01f31dfb 2932 {
e3b88685 2933 buf->st_mode = S_IFDIR;
93e0f0da
JR
2934 }
2935 else
2936 {
2937 switch (GetFileType (fh))
2938 {
2939 case FILE_TYPE_DISK:
e3b88685 2940 buf->st_mode = S_IFREG;
93e0f0da
JR
2941 break;
2942 case FILE_TYPE_PIPE:
e3b88685 2943 buf->st_mode = S_IFIFO;
93e0f0da
JR
2944 break;
2945 case FILE_TYPE_CHAR:
2946 case FILE_TYPE_UNKNOWN:
2947 default:
e3b88685 2948 buf->st_mode = S_IFCHR;
93e0f0da 2949 }
480b0c5b 2950 }
01f31dfb 2951 CloseHandle (fh);
8aaaec6b
EZ
2952 psd = get_file_security_desc (name);
2953 get_file_owner_and_group (psd, name, buf);
76b3903d
GV
2954 }
2955 else
2956 {
2957 /* Don't bother to make this information more accurate. */
93e0f0da 2958 buf->st_mode = (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ?
e3b88685 2959 S_IFDIR : S_IFREG;
480b0c5b 2960 buf->st_nlink = 1;
76b3903d 2961 fake_inode = 0;
8aaaec6b
EZ
2962
2963 get_file_owner_and_group (NULL, name, buf);
76b3903d 2964 }
70fdbb46 2965 xfree (psd);
76b3903d
GV
2966
2967#if 0
2968 /* Not sure if there is any point in this. */
2969 if (!NILP (Vw32_generate_fake_inodes))
2970 fake_inode = generate_inode_val (name);
2971 else if (fake_inode == 0)
2972 {
2973 /* For want of something better, try to make everything unique. */
2974 static DWORD gen_num = 0;
2975 fake_inode = ++gen_num;
480b0c5b 2976 }
76b3903d
GV
2977#endif
2978
2979 /* MSVC defines _ino_t to be short; other libc's might not. */
2980 if (sizeof (buf->st_ino) == 2)
2981 buf->st_ino = fake_inode ^ (fake_inode >> 16);
2982 else
2983 buf->st_ino = fake_inode;
480b0c5b 2984
fbd6baed 2985 /* volume_info is set indirectly by map_w32_filename */
480b0c5b
GV
2986 buf->st_dev = volume_info.serialnum;
2987 buf->st_rdev = volume_info.serialnum;
2988
480b0c5b 2989
8aaaec6b
EZ
2990 buf->st_size = wfd.nFileSizeHigh;
2991 buf->st_size <<= 32;
2992 buf->st_size += wfd.nFileSizeLow;
480b0c5b
GV
2993
2994 /* Convert timestamps to Unix format. */
2995 buf->st_mtime = convert_time (wfd.ftLastWriteTime);
2996 buf->st_atime = convert_time (wfd.ftLastAccessTime);
2997 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
2998 buf->st_ctime = convert_time (wfd.ftCreationTime);
2999 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
3000
3001 /* determine rwx permissions */
3002 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
e3b88685 3003 permission = S_IREAD;
480b0c5b 3004 else
e3b88685 3005 permission = S_IREAD | S_IWRITE;
177c0ea7 3006
480b0c5b 3007 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
e3b88685 3008 permission |= S_IEXEC;
b3308d2e 3009 else if (is_exec (name))
e3b88685 3010 permission |= S_IEXEC;
480b0c5b
GV
3011
3012 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
3013
3014 return 0;
3015}
3016
16bb7578
GV
3017/* Provide fstat and utime as well as stat for consistent handling of
3018 file timestamps. */
3019int
3020fstat (int desc, struct stat * buf)
3021{
3022 HANDLE fh = (HANDLE) _get_osfhandle (desc);
3023 BY_HANDLE_FILE_INFORMATION info;
e3b88685 3024 unsigned __int64 fake_inode;
16bb7578
GV
3025 int permission;
3026
3027 switch (GetFileType (fh) & ~FILE_TYPE_REMOTE)
3028 {
3029 case FILE_TYPE_DISK:
e3b88685 3030 buf->st_mode = S_IFREG;
16bb7578
GV
3031 if (!GetFileInformationByHandle (fh, &info))
3032 {
3033 errno = EACCES;
3034 return -1;
3035 }
3036 break;
3037 case FILE_TYPE_PIPE:
e3b88685 3038 buf->st_mode = S_IFIFO;
16bb7578
GV
3039 goto non_disk;
3040 case FILE_TYPE_CHAR:
3041 case FILE_TYPE_UNKNOWN:
3042 default:
e3b88685 3043 buf->st_mode = S_IFCHR;
16bb7578
GV
3044 non_disk:
3045 memset (&info, 0, sizeof (info));
3046 info.dwFileAttributes = 0;
3047 info.ftCreationTime = utc_base_ft;
3048 info.ftLastAccessTime = utc_base_ft;
3049 info.ftLastWriteTime = utc_base_ft;
3050 }
3051
3052 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
e3b88685 3053 buf->st_mode = S_IFDIR;
93e0f0da
JR
3054
3055 buf->st_nlink = info.nNumberOfLinks;
3056 /* Might as well use file index to fake inode values, but this
3057 is not guaranteed to be unique unless we keep a handle open
3058 all the time (even then there are situations where it is
3059 not unique). Reputedly, there are at most 48 bits of info
3060 (on NTFS, presumably less on FAT). */
e3b88685
EZ
3061 fake_inode = info.nFileIndexHigh;
3062 fake_inode <<= 32;
3063 fake_inode += info.nFileIndexLow;
16bb7578
GV
3064
3065 /* MSVC defines _ino_t to be short; other libc's might not. */
3066 if (sizeof (buf->st_ino) == 2)
3067 buf->st_ino = fake_inode ^ (fake_inode >> 16);
3068 else
3069 buf->st_ino = fake_inode;
3070
8aaaec6b
EZ
3071 /* Consider files to belong to current user.
3072 FIXME: this should use GetSecurityInfo API, but it is only
3073 available for _WIN32_WINNT >= 0x501. */
07f7980a
EZ
3074 buf->st_uid = dflt_passwd.pw_uid;
3075 buf->st_gid = dflt_passwd.pw_gid;
8aaaec6b
EZ
3076 strcpy (buf->st_uname, dflt_passwd.pw_name);
3077 strcpy (buf->st_gname, dflt_group.gr_name);
16bb7578
GV
3078
3079 buf->st_dev = info.dwVolumeSerialNumber;
3080 buf->st_rdev = info.dwVolumeSerialNumber;
3081
8aaaec6b
EZ
3082 buf->st_size = info.nFileSizeHigh;
3083 buf->st_size <<= 32;
3084 buf->st_size += info.nFileSizeLow;
16bb7578
GV
3085
3086 /* Convert timestamps to Unix format. */
3087 buf->st_mtime = convert_time (info.ftLastWriteTime);
3088 buf->st_atime = convert_time (info.ftLastAccessTime);
3089 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
3090 buf->st_ctime = convert_time (info.ftCreationTime);
3091 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
3092
3093 /* determine rwx permissions */
3094 if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
e3b88685 3095 permission = S_IREAD;
16bb7578 3096 else
e3b88685 3097 permission = S_IREAD | S_IWRITE;
177c0ea7 3098
16bb7578 3099 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
e3b88685 3100 permission |= S_IEXEC;
16bb7578
GV
3101 else
3102 {
3103#if 0 /* no way of knowing the filename */
3104 char * p = strrchr (name, '.');
3105 if (p != NULL &&
05131107
JR
3106 (xstrcasecmp (p, ".exe") == 0 ||
3107 xstrcasecmp (p, ".com") == 0 ||
3108 xstrcasecmp (p, ".bat") == 0 ||
3109 xstrcasecmp (p, ".cmd") == 0))
e3b88685 3110 permission |= S_IEXEC;
16bb7578
GV
3111#endif
3112 }
3113
3114 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
3115
3116 return 0;
3117}
3118
3119int
3120utime (const char *name, struct utimbuf *times)
3121{
3122 struct utimbuf deftime;
3123 HANDLE fh;
3124 FILETIME mtime;
3125 FILETIME atime;
3126
3127 if (times == NULL)
3128 {
3129 deftime.modtime = deftime.actime = time (NULL);
3130 times = &deftime;
3131 }
3132
3133 /* Need write access to set times. */
3134 fh = CreateFile (name, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
3135 0, OPEN_EXISTING, 0, NULL);
3136 if (fh)
3137 {
3138 convert_from_time_t (times->actime, &atime);
3139 convert_from_time_t (times->modtime, &mtime);
3140 if (!SetFileTime (fh, NULL, &atime, &mtime))
3141 {
3142 CloseHandle (fh);
3143 errno = EACCES;
3144 return -1;
3145 }
3146 CloseHandle (fh);
3147 }
3148 else
3149 {
3150 errno = EINVAL;
3151 return -1;
3152 }
3153 return 0;
3154}
3155
480b0c5b
GV
3156#ifdef HAVE_SOCKETS
3157
3158/* Wrappers for winsock functions to map between our file descriptors
3159 and winsock's handles; also set h_errno for convenience.
3160
3161 To allow Emacs to run on systems which don't have winsock support
3162 installed, we dynamically link to winsock on startup if present, and
3163 otherwise provide the minimum necessary functionality
3164 (eg. gethostname). */
3165
3166/* function pointers for relevant socket functions */
3167int (PASCAL *pfn_WSAStartup) (WORD wVersionRequired, LPWSADATA lpWSAData);
3168void (PASCAL *pfn_WSASetLastError) (int iError);
3169int (PASCAL *pfn_WSAGetLastError) (void);
26fb7bc4 3170int (PASCAL *pfn_WSAEventSelect) (SOCKET s, HANDLE hEventObject, long lNetworkEvents);
64570b36
KS
3171HANDLE (PASCAL *pfn_WSACreateEvent) (void);
3172int (PASCAL *pfn_WSACloseEvent) (HANDLE hEvent);
480b0c5b
GV
3173int (PASCAL *pfn_socket) (int af, int type, int protocol);
3174int (PASCAL *pfn_bind) (SOCKET s, const struct sockaddr *addr, int namelen);
3175int (PASCAL *pfn_connect) (SOCKET s, const struct sockaddr *addr, int namelen);
3176int (PASCAL *pfn_ioctlsocket) (SOCKET s, long cmd, u_long *argp);
3177int (PASCAL *pfn_recv) (SOCKET s, char * buf, int len, int flags);
3178int (PASCAL *pfn_send) (SOCKET s, const char * buf, int len, int flags);
3179int (PASCAL *pfn_closesocket) (SOCKET s);
3180int (PASCAL *pfn_shutdown) (SOCKET s, int how);
3181int (PASCAL *pfn_WSACleanup) (void);
3182
3183u_short (PASCAL *pfn_htons) (u_short hostshort);
3184u_short (PASCAL *pfn_ntohs) (u_short netshort);
3185unsigned long (PASCAL *pfn_inet_addr) (const char * cp);
3186int (PASCAL *pfn_gethostname) (char * name, int namelen);
3187struct hostent * (PASCAL *pfn_gethostbyname) (const char * name);
3188struct servent * (PASCAL *pfn_getservbyname) (const char * name, const char * proto);
ecd270eb 3189int (PASCAL *pfn_getpeername) (SOCKET s, struct sockaddr *addr, int * namelen);
962955c5
JR
3190int (PASCAL *pfn_setsockopt) (SOCKET s, int level, int optname,
3191 const char * optval, int optlen);
3192int (PASCAL *pfn_listen) (SOCKET s, int backlog);
3193int (PASCAL *pfn_getsockname) (SOCKET s, struct sockaddr * name,
3194 int * namelen);
3195SOCKET (PASCAL *pfn_accept) (SOCKET s, struct sockaddr * addr, int * addrlen);
3196int (PASCAL *pfn_recvfrom) (SOCKET s, char * buf, int len, int flags,
3197 struct sockaddr * from, int * fromlen);
3198int (PASCAL *pfn_sendto) (SOCKET s, const char * buf, int len, int flags,
3199 const struct sockaddr * to, int tolen);
3200
f1614061
RS
3201/* SetHandleInformation is only needed to make sockets non-inheritable. */
3202BOOL (WINAPI *pfn_SetHandleInformation) (HANDLE object, DWORD mask, DWORD flags);
3203#ifndef HANDLE_FLAG_INHERIT
3204#define HANDLE_FLAG_INHERIT 1
3205#endif
480b0c5b 3206
f249a012
RS
3207HANDLE winsock_lib;
3208static int winsock_inuse;
480b0c5b 3209
f249a012 3210BOOL
480b0c5b
GV
3211term_winsock (void)
3212{
f249a012 3213 if (winsock_lib != NULL && winsock_inuse == 0)
480b0c5b 3214 {
f249a012
RS
3215 /* Not sure what would cause WSAENETDOWN, or even if it can happen
3216 after WSAStartup returns successfully, but it seems reasonable
3217 to allow unloading winsock anyway in that case. */
3218 if (pfn_WSACleanup () == 0 ||
3219 pfn_WSAGetLastError () == WSAENETDOWN)
3220 {
3221 if (FreeLibrary (winsock_lib))
3222 winsock_lib = NULL;
3223 return TRUE;
3224 }
480b0c5b 3225 }
f249a012 3226 return FALSE;
480b0c5b
GV
3227}
3228
f249a012
RS
3229BOOL
3230init_winsock (int load_now)
480b0c5b
GV
3231{
3232 WSADATA winsockData;
3233
f249a012
RS
3234 if (winsock_lib != NULL)
3235 return TRUE;
f1614061
RS
3236
3237 pfn_SetHandleInformation = NULL;
3238 pfn_SetHandleInformation
3239 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
3240 "SetHandleInformation");
3241
64570b36 3242 winsock_lib = LoadLibrary ("Ws2_32.dll");
480b0c5b
GV
3243
3244 if (winsock_lib != NULL)
3245 {
3246 /* dynamically link to socket functions */
3247
3248#define LOAD_PROC(fn) \
3249 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
3250 goto fail;
3251
3252 LOAD_PROC( WSAStartup );
3253 LOAD_PROC( WSASetLastError );
3254 LOAD_PROC( WSAGetLastError );
26fb7bc4 3255 LOAD_PROC( WSAEventSelect );
64570b36
KS
3256 LOAD_PROC( WSACreateEvent );
3257 LOAD_PROC( WSACloseEvent );
480b0c5b
GV
3258 LOAD_PROC( socket );
3259 LOAD_PROC( bind );
3260 LOAD_PROC( connect );
3261 LOAD_PROC( ioctlsocket );
3262 LOAD_PROC( recv );
3263 LOAD_PROC( send );
3264 LOAD_PROC( closesocket );
3265 LOAD_PROC( shutdown );
3266 LOAD_PROC( htons );
3267 LOAD_PROC( ntohs );
3268 LOAD_PROC( inet_addr );
3269 LOAD_PROC( gethostname );
3270 LOAD_PROC( gethostbyname );
3271 LOAD_PROC( getservbyname );
ecd270eb 3272 LOAD_PROC( getpeername );
480b0c5b 3273 LOAD_PROC( WSACleanup );
962955c5
JR
3274 LOAD_PROC( setsockopt );
3275 LOAD_PROC( listen );
3276 LOAD_PROC( getsockname );
3277 LOAD_PROC( accept );
3278 LOAD_PROC( recvfrom );
3279 LOAD_PROC( sendto );
f249a012
RS
3280#undef LOAD_PROC
3281
480b0c5b
GV
3282 /* specify version 1.1 of winsock */
3283 if (pfn_WSAStartup (0x101, &winsockData) == 0)
3284 {
f249a012
RS
3285 if (winsockData.wVersion != 0x101)
3286 goto fail;
3287
3288 if (!load_now)
3289 {
3290 /* Report that winsock exists and is usable, but leave
3291 socket functions disabled. I am assuming that calling
3292 WSAStartup does not require any network interaction,
3293 and in particular does not cause or require a dial-up
3294 connection to be established. */
3295
3296 pfn_WSACleanup ();
3297 FreeLibrary (winsock_lib);
3298 winsock_lib = NULL;
3299 }
3300 winsock_inuse = 0;
3301 return TRUE;
480b0c5b
GV
3302 }
3303
3304 fail:
3305 FreeLibrary (winsock_lib);
f249a012 3306 winsock_lib = NULL;
480b0c5b 3307 }
f249a012
RS
3308
3309 return FALSE;
480b0c5b
GV
3310}
3311
3312
3313int h_errno = 0;
3314
3315/* function to set h_errno for compatability; map winsock error codes to
3316 normal system codes where they overlap (non-overlapping definitions
3317 are already in <sys/socket.h> */
9bfb11f9
KS
3318static void
3319set_errno ()
480b0c5b 3320{
f249a012 3321 if (winsock_lib == NULL)
480b0c5b
GV
3322 h_errno = EINVAL;
3323 else
3324 h_errno = pfn_WSAGetLastError ();
3325
3326 switch (h_errno)
3327 {
3328 case WSAEACCES: h_errno = EACCES; break;
3329 case WSAEBADF: h_errno = EBADF; break;
3330 case WSAEFAULT: h_errno = EFAULT; break;
3331 case WSAEINTR: h_errno = EINTR; break;
3332 case WSAEINVAL: h_errno = EINVAL; break;
3333 case WSAEMFILE: h_errno = EMFILE; break;
3334 case WSAENAMETOOLONG: h_errno = ENAMETOOLONG; break;
3335 case WSAENOTEMPTY: h_errno = ENOTEMPTY; break;
3336 }
3337 errno = h_errno;
3338}
3339
9bfb11f9
KS
3340static void
3341check_errno ()
480b0c5b 3342{
f249a012 3343 if (h_errno == 0 && winsock_lib != NULL)
480b0c5b
GV
3344 pfn_WSASetLastError (0);
3345}
3346
d8fcc1b9
AI
3347/* Extend strerror to handle the winsock-specific error codes. */
3348struct {
3349 int errnum;
3350 char * msg;
3351} _wsa_errlist[] = {
3352 WSAEINTR , "Interrupted function call",
3353 WSAEBADF , "Bad file descriptor",
3354 WSAEACCES , "Permission denied",
3355 WSAEFAULT , "Bad address",
3356 WSAEINVAL , "Invalid argument",
3357 WSAEMFILE , "Too many open files",
177c0ea7 3358
d8fcc1b9
AI
3359 WSAEWOULDBLOCK , "Resource temporarily unavailable",
3360 WSAEINPROGRESS , "Operation now in progress",
3361 WSAEALREADY , "Operation already in progress",
3362 WSAENOTSOCK , "Socket operation on non-socket",
3363 WSAEDESTADDRREQ , "Destination address required",
3364 WSAEMSGSIZE , "Message too long",
3365 WSAEPROTOTYPE , "Protocol wrong type for socket",
3366 WSAENOPROTOOPT , "Bad protocol option",
3367 WSAEPROTONOSUPPORT , "Protocol not supported",
3368 WSAESOCKTNOSUPPORT , "Socket type not supported",
3369 WSAEOPNOTSUPP , "Operation not supported",
3370 WSAEPFNOSUPPORT , "Protocol family not supported",
3371 WSAEAFNOSUPPORT , "Address family not supported by protocol family",
3372 WSAEADDRINUSE , "Address already in use",
3373 WSAEADDRNOTAVAIL , "Cannot assign requested address",
3374 WSAENETDOWN , "Network is down",
3375 WSAENETUNREACH , "Network is unreachable",
3376 WSAENETRESET , "Network dropped connection on reset",
3377 WSAECONNABORTED , "Software caused connection abort",
3378 WSAECONNRESET , "Connection reset by peer",
3379 WSAENOBUFS , "No buffer space available",
3380 WSAEISCONN , "Socket is already connected",
3381 WSAENOTCONN , "Socket is not connected",
3382 WSAESHUTDOWN , "Cannot send after socket shutdown",
3383 WSAETOOMANYREFS , "Too many references", /* not sure */
3384 WSAETIMEDOUT , "Connection timed out",
3385 WSAECONNREFUSED , "Connection refused",
3386 WSAELOOP , "Network loop", /* not sure */
3387 WSAENAMETOOLONG , "Name is too long",
3388 WSAEHOSTDOWN , "Host is down",
3389 WSAEHOSTUNREACH , "No route to host",
3390 WSAENOTEMPTY , "Buffer not empty", /* not sure */
3391 WSAEPROCLIM , "Too many processes",
3392 WSAEUSERS , "Too many users", /* not sure */
3393 WSAEDQUOT , "Double quote in host name", /* really not sure */
3394 WSAESTALE , "Data is stale", /* not sure */
3395 WSAEREMOTE , "Remote error", /* not sure */
177c0ea7 3396
d8fcc1b9
AI
3397 WSASYSNOTREADY , "Network subsystem is unavailable",
3398 WSAVERNOTSUPPORTED , "WINSOCK.DLL version out of range",
3399 WSANOTINITIALISED , "Winsock not initialized successfully",
3400 WSAEDISCON , "Graceful shutdown in progress",
3401#ifdef WSAENOMORE
3402 WSAENOMORE , "No more operations allowed", /* not sure */
3403 WSAECANCELLED , "Operation cancelled", /* not sure */
3404 WSAEINVALIDPROCTABLE , "Invalid procedure table from service provider",
3405 WSAEINVALIDPROVIDER , "Invalid service provider version number",
3406 WSAEPROVIDERFAILEDINIT , "Unable to initialize a service provider",
aa5ee2a3 3407 WSASYSCALLFAILURE , "System call failure",
d8fcc1b9
AI
3408 WSASERVICE_NOT_FOUND , "Service not found", /* not sure */
3409 WSATYPE_NOT_FOUND , "Class type not found",
3410 WSA_E_NO_MORE , "No more resources available", /* really not sure */
3411 WSA_E_CANCELLED , "Operation already cancelled", /* really not sure */
3412 WSAEREFUSED , "Operation refused", /* not sure */
3413#endif
177c0ea7 3414
d8fcc1b9
AI
3415 WSAHOST_NOT_FOUND , "Host not found",
3416 WSATRY_AGAIN , "Authoritative host not found during name lookup",
3417 WSANO_RECOVERY , "Non-recoverable error during name lookup",
3418 WSANO_DATA , "Valid name, no data record of requested type",
3419
3420 -1, NULL
3421};
3422
3423char *
3424sys_strerror(int error_no)
3425{
3426 int i;
3427 static char unknown_msg[40];
3428
a302c7ae
AI
3429 if (error_no >= 0 && error_no < sys_nerr)
3430 return sys_errlist[error_no];
d8fcc1b9
AI
3431
3432 for (i = 0; _wsa_errlist[i].errnum >= 0; i++)
3433 if (_wsa_errlist[i].errnum == error_no)
3434 return _wsa_errlist[i].msg;
3435
3436 sprintf(unknown_msg, "Unidentified error: %d", error_no);
3437 return unknown_msg;
3438}
3439
480b0c5b
GV
3440/* [andrewi 3-May-96] I've had conflicting results using both methods,
3441 but I believe the method of keeping the socket handle separate (and
3442 insuring it is not inheritable) is the correct one. */
3443
3444//#define SOCK_REPLACE_HANDLE
3445
3446#ifdef SOCK_REPLACE_HANDLE
3447#define SOCK_HANDLE(fd) ((SOCKET) _get_osfhandle (fd))
3448#else
3449#define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
3450#endif
3451
962955c5
JR
3452int socket_to_fd (SOCKET s);
3453
480b0c5b
GV
3454int
3455sys_socket(int af, int type, int protocol)
3456{
962955c5 3457 SOCKET s;
480b0c5b 3458
f249a012 3459 if (winsock_lib == NULL)
480b0c5b
GV
3460 {
3461 h_errno = ENETDOWN;
3462 return INVALID_SOCKET;
3463 }
3464
3465 check_errno ();
3466
3467 /* call the real socket function */
962955c5 3468 s = pfn_socket (af, type, protocol);
177c0ea7 3469
480b0c5b 3470 if (s != INVALID_SOCKET)
962955c5 3471 return socket_to_fd (s);
480b0c5b 3472
962955c5
JR
3473 set_errno ();
3474 return -1;
3475}
3476
3477/* Convert a SOCKET to a file descriptor. */
3478int
3479socket_to_fd (SOCKET s)
3480{
3481 int fd;
3482 child_process * cp;
3483
3484 /* Although under NT 3.5 _open_osfhandle will accept a socket
3485 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
3486 that does not work under NT 3.1. However, we can get the same
3487 effect by using a backdoor function to replace an existing
3488 descriptor handle with the one we want. */
3489
3490 /* allocate a file descriptor (with appropriate flags) */
3491 fd = _open ("NUL:", _O_RDWR);
3492 if (fd >= 0)
3493 {
480b0c5b 3494#ifdef SOCK_REPLACE_HANDLE
962955c5
JR
3495 /* now replace handle to NUL with our socket handle */
3496 CloseHandle ((HANDLE) _get_osfhandle (fd));
3497 _free_osfhnd (fd);
3498 _set_osfhnd (fd, s);
3499 /* setmode (fd, _O_BINARY); */
480b0c5b 3500#else
962955c5
JR
3501 /* Make a non-inheritable copy of the socket handle. Note
3502 that it is possible that sockets aren't actually kernel
3503 handles, which appears to be the case on Windows 9x when
3504 the MS Proxy winsock client is installed. */
3505 {
3506 /* Apparently there is a bug in NT 3.51 with some service
3507 packs, which prevents using DuplicateHandle to make a
3508 socket handle non-inheritable (causes WSACleanup to
3509 hang). The work-around is to use SetHandleInformation
3510 instead if it is available and implemented. */
3511 if (pfn_SetHandleInformation)
480b0c5b 3512 {
962955c5
JR
3513 pfn_SetHandleInformation ((HANDLE) s, HANDLE_FLAG_INHERIT, 0);
3514 }
3515 else
3516 {
3517 HANDLE parent = GetCurrentProcess ();
3518 HANDLE new_s = INVALID_HANDLE_VALUE;
3519
3520 if (DuplicateHandle (parent,
3521 (HANDLE) s,
3522 parent,
3523 &new_s,
3524 0,
3525 FALSE,
3526 DUPLICATE_SAME_ACCESS))
f1614061 3527 {
962955c5
JR
3528 /* It is possible that DuplicateHandle succeeds even
3529 though the socket wasn't really a kernel handle,
3530 because a real handle has the same value. So
3531 test whether the new handle really is a socket. */
3532 long nonblocking = 0;
3533 if (pfn_ioctlsocket ((SOCKET) new_s, FIONBIO, &nonblocking) == 0)
ca149beb 3534 {
962955c5
JR
3535 pfn_closesocket (s);
3536 s = (SOCKET) new_s;
3537 }
3538 else
3539 {
3540 CloseHandle (new_s);
3541 }
177c0ea7 3542 }
480b0c5b 3543 }
962955c5
JR
3544 }
3545 fd_info[fd].hnd = (HANDLE) s;
480b0c5b
GV
3546#endif
3547
962955c5
JR
3548 /* set our own internal flags */
3549 fd_info[fd].flags = FILE_SOCKET | FILE_BINARY | FILE_READ | FILE_WRITE;
480b0c5b 3550
962955c5
JR
3551 cp = new_child ();
3552 if (cp)
3553 {
3554 cp->fd = fd;
3555 cp->status = STATUS_READ_ACKNOWLEDGED;
480b0c5b 3556
962955c5
JR
3557 /* attach child_process to fd_info */
3558 if (fd_info[ fd ].cp != NULL)
3559 {
3560 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd));
3561 abort ();
480b0c5b
GV
3562 }
3563
962955c5
JR
3564 fd_info[ fd ].cp = cp;
3565
3566 /* success! */
3567 winsock_inuse++; /* count open sockets */
3568 return fd;
480b0c5b 3569 }
480b0c5b 3570
962955c5
JR
3571 /* clean up */
3572 _close (fd);
3573 }
3574 pfn_closesocket (s);
3575 h_errno = EMFILE;
480b0c5b
GV
3576 return -1;
3577}
3578
3579
3580int
3581sys_bind (int s, const struct sockaddr * addr, int namelen)
3582{
f249a012 3583 if (winsock_lib == NULL)
480b0c5b
GV
3584 {
3585 h_errno = ENOTSOCK;
3586 return SOCKET_ERROR;
3587 }
3588
3589 check_errno ();
3590 if (fd_info[s].flags & FILE_SOCKET)
3591 {
3592 int rc = pfn_bind (SOCK_HANDLE (s), addr, namelen);
3593 if (rc == SOCKET_ERROR)
3594 set_errno ();
3595 return rc;
3596 }
3597 h_errno = ENOTSOCK;
3598 return SOCKET_ERROR;
3599}
3600
3601
3602int
3603sys_connect (int s, const struct sockaddr * name, int namelen)
3604{
f249a012 3605 if (winsock_lib == NULL)
480b0c5b
GV
3606 {
3607 h_errno = ENOTSOCK;
3608 return SOCKET_ERROR;
3609 }
3610
3611 check_errno ();
3612 if (fd_info[s].flags & FILE_SOCKET)
3613 {
3614 int rc = pfn_connect (SOCK_HANDLE (s), name, namelen);
3615 if (rc == SOCKET_ERROR)
3616 set_errno ();
3617 return rc;
3618 }
3619 h_errno = ENOTSOCK;
3620 return SOCKET_ERROR;
3621}
3622
3623u_short
3624sys_htons (u_short hostshort)
3625{
f249a012 3626 return (winsock_lib != NULL) ?
480b0c5b
GV
3627 pfn_htons (hostshort) : hostshort;
3628}
3629
3630u_short
3631sys_ntohs (u_short netshort)
3632{
f249a012 3633 return (winsock_lib != NULL) ?
480b0c5b
GV
3634 pfn_ntohs (netshort) : netshort;
3635}
3636
3637unsigned long
3638sys_inet_addr (const char * cp)
3639{
f249a012 3640 return (winsock_lib != NULL) ?
480b0c5b
GV
3641 pfn_inet_addr (cp) : INADDR_NONE;
3642}
3643
3644int
3645sys_gethostname (char * name, int namelen)
3646{
f249a012 3647 if (winsock_lib != NULL)
480b0c5b
GV
3648 return pfn_gethostname (name, namelen);
3649
3650 if (namelen > MAX_COMPUTERNAME_LENGTH)
a302c7ae 3651 return !GetComputerName (name, (DWORD *)&namelen);
480b0c5b
GV
3652
3653 h_errno = EFAULT;
3654 return SOCKET_ERROR;
3655}
3656
3657struct hostent *
3658sys_gethostbyname(const char * name)
3659{
3660 struct hostent * host;
3661
f249a012 3662 if (winsock_lib == NULL)
480b0c5b
GV
3663 {
3664 h_errno = ENETDOWN;
3665 return NULL;
3666 }
3667
3668 check_errno ();
3669 host = pfn_gethostbyname (name);
3670 if (!host)
3671 set_errno ();
3672 return host;
3673}
3674
3675struct servent *
3676sys_getservbyname(const char * name, const char * proto)
3677{
3678 struct servent * serv;
3679
f249a012 3680 if (winsock_lib == NULL)
480b0c5b
GV
3681 {
3682 h_errno = ENETDOWN;
3683 return NULL;
3684 }
3685
3686 check_errno ();
3687 serv = pfn_getservbyname (name, proto);
3688 if (!serv)
3689 set_errno ();
3690 return serv;
3691}
3692
ecd270eb
JR
3693int
3694sys_getpeername (int s, struct sockaddr *addr, int * namelen)
3695{
3696 if (winsock_lib == NULL)
3697 {
3698 h_errno = ENETDOWN;
3699 return SOCKET_ERROR;
3700 }
3701
3702 check_errno ();
3703 if (fd_info[s].flags & FILE_SOCKET)
3704 {
3705 int rc = pfn_getpeername (SOCK_HANDLE (s), addr, namelen);
3706 if (rc == SOCKET_ERROR)
3707 set_errno ();
3708 return rc;
3709 }
3710 h_errno = ENOTSOCK;
3711 return SOCKET_ERROR;
3712}
3713
3714
380961a6
GV
3715int
3716sys_shutdown (int s, int how)
3717{
380961a6
GV
3718 if (winsock_lib == NULL)
3719 {
3720 h_errno = ENETDOWN;
3721 return SOCKET_ERROR;
3722 }
3723
3724 check_errno ();
3725 if (fd_info[s].flags & FILE_SOCKET)
3726 {
3727 int rc = pfn_shutdown (SOCK_HANDLE (s), how);
962955c5
JR
3728 if (rc == SOCKET_ERROR)
3729 set_errno ();
3730 return rc;
3731 }
3732 h_errno = ENOTSOCK;
3733 return SOCKET_ERROR;
3734}
3735
3736int
a5a389bb 3737sys_setsockopt (int s, int level, int optname, const void * optval, int optlen)
962955c5
JR
3738{
3739 if (winsock_lib == NULL)
3740 {
3741 h_errno = ENETDOWN;
3742 return SOCKET_ERROR;
3743 }
3744
3745 check_errno ();
3746 if (fd_info[s].flags & FILE_SOCKET)
3747 {
3748 int rc = pfn_setsockopt (SOCK_HANDLE (s), level, optname,
a5a389bb 3749 (const char *)optval, optlen);
962955c5
JR
3750 if (rc == SOCKET_ERROR)
3751 set_errno ();
3752 return rc;
3753 }
3754 h_errno = ENOTSOCK;
177c0ea7 3755 return SOCKET_ERROR;
962955c5
JR
3756}
3757
3758int
3759sys_listen (int s, int backlog)
3760{
3761 if (winsock_lib == NULL)
3762 {
3763 h_errno = ENETDOWN;
3764 return SOCKET_ERROR;
3765 }
3766
3767 check_errno ();
3768 if (fd_info[s].flags & FILE_SOCKET)
3769 {
3770 int rc = pfn_listen (SOCK_HANDLE (s), backlog);
3771 if (rc == SOCKET_ERROR)
3772 set_errno ();
26fb7bc4 3773 else
64570b36 3774 fd_info[s].flags |= FILE_LISTEN;
962955c5
JR
3775 return rc;
3776 }
3777 h_errno = ENOTSOCK;
177c0ea7 3778 return SOCKET_ERROR;
962955c5
JR
3779}
3780
3781int
3782sys_getsockname (int s, struct sockaddr * name, int * namelen)
3783{
3784 if (winsock_lib == NULL)
3785 {
3786 h_errno = ENETDOWN;
3787 return SOCKET_ERROR;
3788 }
3789
3790 check_errno ();
3791 if (fd_info[s].flags & FILE_SOCKET)
3792 {
3793 int rc = pfn_getsockname (SOCK_HANDLE (s), name, namelen);
3794 if (rc == SOCKET_ERROR)
3795 set_errno ();
3796 return rc;
3797 }
3798 h_errno = ENOTSOCK;
177c0ea7 3799 return SOCKET_ERROR;
962955c5
JR
3800}
3801
3802int
3803sys_accept (int s, struct sockaddr * addr, int * addrlen)
3804{
3805 if (winsock_lib == NULL)
3806 {
3807 h_errno = ENETDOWN;
3808 return -1;
3809 }
3810
3811 check_errno ();
26fb7bc4 3812 if (fd_info[s].flags & FILE_LISTEN)
962955c5 3813 {
a0ad1860 3814 SOCKET t = pfn_accept (SOCK_HANDLE (s), addr, addrlen);
64570b36
KS
3815 int fd = -1;
3816 if (t == INVALID_SOCKET)
3817 set_errno ();
3818 else
3819 fd = socket_to_fd (t);
962955c5 3820
64570b36
KS
3821 fd_info[s].cp->status = STATUS_READ_ACKNOWLEDGED;
3822 ResetEvent (fd_info[s].cp->char_avail);
3823 return fd;
962955c5
JR
3824 }
3825 h_errno = ENOTSOCK;
3826 return -1;
3827}
3828
3829int
3830sys_recvfrom (int s, char * buf, int len, int flags,
3831 struct sockaddr * from, int * fromlen)
3832{
3833 if (winsock_lib == NULL)
3834 {
3835 h_errno = ENETDOWN;
3836 return SOCKET_ERROR;
3837 }
3838
3839 check_errno ();
3840 if (fd_info[s].flags & FILE_SOCKET)
3841 {
3842 int rc = pfn_recvfrom (SOCK_HANDLE (s), buf, len, flags, from, fromlen);
3843 if (rc == SOCKET_ERROR)
3844 set_errno ();
3845 return rc;
3846 }
3847 h_errno = ENOTSOCK;
3848 return SOCKET_ERROR;
3849}
3850
3851int
3852sys_sendto (int s, const char * buf, int len, int flags,
3853 const struct sockaddr * to, int tolen)
3854{
3855 if (winsock_lib == NULL)
3856 {
3857 h_errno = ENETDOWN;
3858 return SOCKET_ERROR;
3859 }
3860
3861 check_errno ();
3862 if (fd_info[s].flags & FILE_SOCKET)
3863 {
3864 int rc = pfn_sendto (SOCK_HANDLE (s), buf, len, flags, to, tolen);
380961a6
GV
3865 if (rc == SOCKET_ERROR)
3866 set_errno ();
3867 return rc;
3868 }
3869 h_errno = ENOTSOCK;
3870 return SOCKET_ERROR;
3871}
3872
ecd270eb
JR
3873/* Windows does not have an fcntl function. Provide an implementation
3874 solely for making sockets non-blocking. */
3875int
3876fcntl (int s, int cmd, int options)
3877{
3878 if (winsock_lib == NULL)
3879 {
3880 h_errno = ENETDOWN;
3881 return -1;
3882 }
3883
3884 check_errno ();
3885 if (fd_info[s].flags & FILE_SOCKET)
3886 {
3887 if (cmd == F_SETFL && options == O_NDELAY)
3888 {
3889 unsigned long nblock = 1;
3890 int rc = pfn_ioctlsocket (SOCK_HANDLE (s), FIONBIO, &nblock);
3891 if (rc == SOCKET_ERROR)
3892 set_errno();
3893 /* Keep track of the fact that we set this to non-blocking. */
3894 fd_info[s].flags |= FILE_NDELAY;
3895 return rc;
3896 }
3897 else
3898 {
3899 h_errno = EINVAL;
3900 return SOCKET_ERROR;
3901 }
3902 }
3903 h_errno = ENOTSOCK;
3904 return SOCKET_ERROR;
3905}
3906
480b0c5b
GV
3907#endif /* HAVE_SOCKETS */
3908
3909
3910/* Shadow main io functions: we need to handle pipes and sockets more
3911 intelligently, and implement non-blocking mode as well. */
3912
3913int
3914sys_close (int fd)
3915{
3916 int rc;
3917
7559f399 3918 if (fd < 0)
480b0c5b
GV
3919 {
3920 errno = EBADF;
3921 return -1;
3922 }
3923
7559f399 3924 if (fd < MAXDESC && fd_info[fd].cp)
480b0c5b
GV
3925 {
3926 child_process * cp = fd_info[fd].cp;
3927
3928 fd_info[fd].cp = NULL;
3929
3930 if (CHILD_ACTIVE (cp))
3931 {
3932 /* if last descriptor to active child_process then cleanup */
3933 int i;
3934 for (i = 0; i < MAXDESC; i++)
3935 {
3936 if (i == fd)
3937 continue;
3938 if (fd_info[i].cp == cp)
3939 break;
3940 }
3941 if (i == MAXDESC)
3942 {
f249a012 3943#ifdef HAVE_SOCKETS
480b0c5b
GV
3944 if (fd_info[fd].flags & FILE_SOCKET)
3945 {
f249a012
RS
3946#ifndef SOCK_REPLACE_HANDLE
3947 if (winsock_lib == NULL) abort ();
480b0c5b
GV
3948
3949 pfn_shutdown (SOCK_HANDLE (fd), 2);
3950 rc = pfn_closesocket (SOCK_HANDLE (fd));
f249a012
RS
3951#endif
3952 winsock_inuse--; /* count open sockets */
480b0c5b
GV
3953 }
3954#endif
3955 delete_child (cp);
3956 }
3957 }
3958 }
3959
3960 /* Note that sockets do not need special treatment here (at least on
e9e23e23 3961 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
480b0c5b
GV
3962 closesocket is equivalent to CloseHandle, which is to be expected
3963 because socket handles are fully fledged kernel handles. */
3964 rc = _close (fd);
3965
7559f399 3966 if (rc == 0 && fd < MAXDESC)
480b0c5b
GV
3967 fd_info[fd].flags = 0;
3968
3969 return rc;
3970}
3971
3972int
3973sys_dup (int fd)
3974{
3975 int new_fd;
3976
3977 new_fd = _dup (fd);
7559f399 3978 if (new_fd >= 0 && new_fd < MAXDESC)
480b0c5b
GV
3979 {
3980 /* duplicate our internal info as well */
3981 fd_info[new_fd] = fd_info[fd];
3982 }
3983 return new_fd;
3984}
3985
3986
3987int
3988sys_dup2 (int src, int dst)
3989{
3990 int rc;
3991
3992 if (dst < 0 || dst >= MAXDESC)
3993 {
3994 errno = EBADF;
3995 return -1;
3996 }
3997
3998 /* make sure we close the destination first if it's a pipe or socket */
3999 if (src != dst && fd_info[dst].flags != 0)
4000 sys_close (dst);
177c0ea7 4001
480b0c5b
GV
4002 rc = _dup2 (src, dst);
4003 if (rc == 0)
4004 {
4005 /* duplicate our internal info as well */
4006 fd_info[dst] = fd_info[src];
4007 }
4008 return rc;
4009}
4010
480b0c5b
GV
4011/* Unix pipe() has only one arg */
4012int
4013sys_pipe (int * phandles)
4014{
4015 int rc;
4016 unsigned flags;
480b0c5b 4017
76b3903d
GV
4018 /* make pipe handles non-inheritable; when we spawn a child, we
4019 replace the relevant handle with an inheritable one. Also put
4020 pipes into binary mode; we will do text mode translation ourselves
4021 if required. */
4022 rc = _pipe (phandles, 0, _O_NOINHERIT | _O_BINARY);
480b0c5b
GV
4023
4024 if (rc == 0)
4025 {
cb72110d
JR
4026 /* Protect against overflow, since Windows can open more handles than
4027 our fd_info array has room for. */
4028 if (phandles[0] >= MAXDESC || phandles[1] >= MAXDESC)
4029 {
4030 _close (phandles[0]);
4031 _close (phandles[1]);
4032 rc = -1;
4033 }
4034 else
4035 {
4036 flags = FILE_PIPE | FILE_READ | FILE_BINARY;
4037 fd_info[phandles[0]].flags = flags;
480b0c5b 4038
cb72110d
JR
4039 flags = FILE_PIPE | FILE_WRITE | FILE_BINARY;
4040 fd_info[phandles[1]].flags = flags;
4041 }
480b0c5b
GV
4042 }
4043
4044 return rc;
4045}
4046
f7554349 4047/* From ntproc.c */
78806724 4048extern int w32_pipe_read_delay;
f7554349 4049
480b0c5b
GV
4050/* Function to do blocking read of one byte, needed to implement
4051 select. It is only allowed on sockets and pipes. */
4052int
4053_sys_read_ahead (int fd)
4054{
4055 child_process * cp;
4056 int rc;
4057
4058 if (fd < 0 || fd >= MAXDESC)
4059 return STATUS_READ_ERROR;
4060
4061 cp = fd_info[fd].cp;
4062
4063 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
4064 return STATUS_READ_ERROR;
4065
4066 if ((fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET)) == 0
4067 || (fd_info[fd].flags & FILE_READ) == 0)
4068 {
4069 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe or socket!\n", fd));
4070 abort ();
4071 }
177c0ea7 4072
480b0c5b 4073 cp->status = STATUS_READ_IN_PROGRESS;
177c0ea7 4074
480b0c5b 4075 if (fd_info[fd].flags & FILE_PIPE)
f7554349 4076 {
f7554349
KH
4077 rc = _read (fd, &cp->chr, sizeof (char));
4078
4079 /* Give subprocess time to buffer some more output for us before
e9e23e23 4080 reporting that input is available; we need this because Windows 95
f7554349
KH
4081 connects DOS programs to pipes by making the pipe appear to be
4082 the normal console stdout - as a result most DOS programs will
4083 write to stdout without buffering, ie. one character at a
fbd6baed 4084 time. Even some W32 programs do this - "dir" in a command
f7554349
KH
4085 shell on NT is very slow if we don't do this. */
4086 if (rc > 0)
4087 {
78806724 4088 int wait = w32_pipe_read_delay;
f7554349
KH
4089
4090 if (wait > 0)
4091 Sleep (wait);
4092 else if (wait < 0)
4093 while (++wait <= 0)
4094 /* Yield remainder of our time slice, effectively giving a
4095 temporary priority boost to the child process. */
4096 Sleep (0);
4097 }
4098 }
480b0c5b
GV
4099#ifdef HAVE_SOCKETS
4100 else if (fd_info[fd].flags & FILE_SOCKET)
ecd270eb
JR
4101 {
4102 unsigned long nblock = 0;
4103 /* We always want this to block, so temporarily disable NDELAY. */
4104 if (fd_info[fd].flags & FILE_NDELAY)
4105 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
4106
4107 rc = pfn_recv (SOCK_HANDLE (fd), &cp->chr, sizeof (char), 0);
4108
4109 if (fd_info[fd].flags & FILE_NDELAY)
4110 {
4111 nblock = 1;
4112 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
4113 }
4114 }
480b0c5b 4115#endif
177c0ea7 4116
480b0c5b
GV
4117 if (rc == sizeof (char))
4118 cp->status = STATUS_READ_SUCCEEDED;
4119 else
4120 cp->status = STATUS_READ_FAILED;
4121
4122 return cp->status;
4123}
4124
9bfb11f9
KS
4125int
4126_sys_wait_accept (int fd)
64570b36
KS
4127{
4128 HANDLE hEv;
4129 child_process * cp;
4130 int rc;
4131
4132 if (fd < 0 || fd >= MAXDESC)
4133 return STATUS_READ_ERROR;
4134
4135 cp = fd_info[fd].cp;
4136
4137 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
4138 return STATUS_READ_ERROR;
4139
4140 cp->status = STATUS_READ_FAILED;
4141
4142 hEv = pfn_WSACreateEvent ();
4143 rc = pfn_WSAEventSelect (SOCK_HANDLE (fd), hEv, FD_ACCEPT);
4144 if (rc != SOCKET_ERROR)
4145 {
4146 rc = WaitForSingleObject (hEv, INFINITE);
4147 pfn_WSAEventSelect (SOCK_HANDLE (fd), NULL, 0);
64570b36
KS
4148 if (rc == WAIT_OBJECT_0)
4149 cp->status = STATUS_READ_SUCCEEDED;
4150 }
7046f191 4151 pfn_WSACloseEvent (hEv);
64570b36
KS
4152
4153 return cp->status;
4154}
4155
480b0c5b
GV
4156int
4157sys_read (int fd, char * buffer, unsigned int count)
4158{
4159 int nchars;
480b0c5b
GV
4160 int to_read;
4161 DWORD waiting;
76b3903d 4162 char * orig_buffer = buffer;
480b0c5b 4163
7559f399 4164 if (fd < 0)
480b0c5b
GV
4165 {
4166 errno = EBADF;
4167 return -1;
4168 }
4169
7559f399 4170 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET))
480b0c5b
GV
4171 {
4172 child_process *cp = fd_info[fd].cp;
4173
4174 if ((fd_info[fd].flags & FILE_READ) == 0)
4175 {
4176 errno = EBADF;
4177 return -1;
4178 }
4179
76b3903d
GV
4180 nchars = 0;
4181
4182 /* re-read CR carried over from last read */
4183 if (fd_info[fd].flags & FILE_LAST_CR)
4184 {
4185 if (fd_info[fd].flags & FILE_BINARY) abort ();
4186 *buffer++ = 0x0d;
4187 count--;
4188 nchars++;
f52eb3ef 4189 fd_info[fd].flags &= ~FILE_LAST_CR;
76b3903d
GV
4190 }
4191
480b0c5b
GV
4192 /* presence of a child_process structure means we are operating in
4193 non-blocking mode - otherwise we just call _read directly.
4194 Note that the child_process structure might be missing because
4195 reap_subprocess has been called; in this case the pipe is
4196 already broken, so calling _read on it is okay. */
4197 if (cp)
4198 {
4199 int current_status = cp->status;
4200
4201 switch (current_status)
4202 {
4203 case STATUS_READ_FAILED:
4204 case STATUS_READ_ERROR:
f52eb3ef
GV
4205 /* report normal EOF if nothing in buffer */
4206 if (nchars <= 0)
4207 fd_info[fd].flags |= FILE_AT_EOF;
4208 return nchars;
480b0c5b
GV
4209
4210 case STATUS_READ_READY:
4211 case STATUS_READ_IN_PROGRESS:
4212 DebPrint (("sys_read called when read is in progress\n"));
4213 errno = EWOULDBLOCK;
4214 return -1;
4215
4216 case STATUS_READ_SUCCEEDED:
4217 /* consume read-ahead char */
4218 *buffer++ = cp->chr;
4219 count--;
76b3903d 4220 nchars++;
480b0c5b
GV
4221 cp->status = STATUS_READ_ACKNOWLEDGED;
4222 ResetEvent (cp->char_avail);
4223
4224 case STATUS_READ_ACKNOWLEDGED:
4225 break;
4226
4227 default:
4228 DebPrint (("sys_read: bad status %d\n", current_status));
4229 errno = EBADF;
4230 return -1;
4231 }
4232
4233 if (fd_info[fd].flags & FILE_PIPE)
4234 {
4235 PeekNamedPipe ((HANDLE) _get_osfhandle (fd), NULL, 0, NULL, &waiting, NULL);
4236 to_read = min (waiting, (DWORD) count);
f52eb3ef
GV
4237
4238 if (to_read > 0)
4239 nchars += _read (fd, buffer, to_read);
480b0c5b
GV
4240 }
4241#ifdef HAVE_SOCKETS
4242 else /* FILE_SOCKET */
4243 {
f249a012 4244 if (winsock_lib == NULL) abort ();
480b0c5b
GV
4245
4246 /* do the equivalent of a non-blocking read */
4247 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONREAD, &waiting);
76b3903d 4248 if (waiting == 0 && nchars == 0)
480b0c5b
GV
4249 {
4250 h_errno = errno = EWOULDBLOCK;
4251 return -1;
4252 }
4253
480b0c5b
GV
4254 if (waiting)
4255 {
4256 /* always use binary mode for sockets */
76b3903d
GV
4257 int res = pfn_recv (SOCK_HANDLE (fd), buffer, count, 0);
4258 if (res == SOCKET_ERROR)
480b0c5b
GV
4259 {
4260 DebPrint(("sys_read.recv failed with error %d on socket %ld\n",
4261 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
76b3903d
GV
4262 set_errno ();
4263 return -1;
480b0c5b 4264 }
76b3903d 4265 nchars += res;
480b0c5b
GV
4266 }
4267 }
4268#endif
4269 }
4270 else
f52eb3ef
GV
4271 {
4272 int nread = _read (fd, buffer, count);
4273 if (nread >= 0)
4274 nchars += nread;
4275 else if (nchars == 0)
4276 nchars = nread;
4277 }
76b3903d 4278
f52eb3ef
GV
4279 if (nchars <= 0)
4280 fd_info[fd].flags |= FILE_AT_EOF;
76b3903d 4281 /* Perform text mode translation if required. */
f52eb3ef 4282 else if ((fd_info[fd].flags & FILE_BINARY) == 0)
76b3903d
GV
4283 {
4284 nchars = crlf_to_lf (nchars, orig_buffer);
4285 /* If buffer contains only CR, return that. To be absolutely
4286 sure we should attempt to read the next char, but in
4287 practice a CR to be followed by LF would not appear by
4288 itself in the buffer. */
4289 if (nchars > 1 && orig_buffer[nchars - 1] == 0x0d)
4290 {
4291 fd_info[fd].flags |= FILE_LAST_CR;
4292 nchars--;
4293 }
76b3903d 4294 }
480b0c5b
GV
4295 }
4296 else
4297 nchars = _read (fd, buffer, count);
4298
76b3903d 4299 return nchars;
480b0c5b
GV
4300}
4301
4302/* For now, don't bother with a non-blocking mode */
4303int
4304sys_write (int fd, const void * buffer, unsigned int count)
4305{
4306 int nchars;
4307
7559f399 4308 if (fd < 0)
480b0c5b
GV
4309 {
4310 errno = EBADF;
4311 return -1;
4312 }
4313
7559f399 4314 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET))
76b3903d
GV
4315 {
4316 if ((fd_info[fd].flags & FILE_WRITE) == 0)
4317 {
4318 errno = EBADF;
4319 return -1;
4320 }
4321
4322 /* Perform text mode translation if required. */
4323 if ((fd_info[fd].flags & FILE_BINARY) == 0)
4324 {
4325 char * tmpbuf = alloca (count * 2);
4326 unsigned char * src = (void *)buffer;
4327 unsigned char * dst = tmpbuf;
4328 int nbytes = count;
4329
4330 while (1)
4331 {
4332 unsigned char *next;
4333 /* copy next line or remaining bytes */
4334 next = _memccpy (dst, src, '\n', nbytes);
4335 if (next)
4336 {
4337 /* copied one line ending with '\n' */
4338 int copied = next - dst;
4339 nbytes -= copied;
4340 src += copied;
4341 /* insert '\r' before '\n' */
4342 next[-1] = '\r';
4343 next[0] = '\n';
4344 dst = next + 1;
4345 count++;
177c0ea7 4346 }
76b3903d
GV
4347 else
4348 /* copied remaining partial line -> now finished */
4349 break;
4350 }
4351 buffer = tmpbuf;
4352 }
4353 }
4354
480b0c5b 4355#ifdef HAVE_SOCKETS
7559f399 4356 if (fd < MAXDESC && fd_info[fd].flags & FILE_SOCKET)
480b0c5b 4357 {
30a32e0e 4358 unsigned long nblock = 0;
f249a012 4359 if (winsock_lib == NULL) abort ();
30a32e0e
JR
4360
4361 /* TODO: implement select() properly so non-blocking I/O works. */
4362 /* For now, make sure the write blocks. */
4363 if (fd_info[fd].flags & FILE_NDELAY)
4364 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
4365
480b0c5b 4366 nchars = pfn_send (SOCK_HANDLE (fd), buffer, count, 0);
30a32e0e
JR
4367
4368 /* Set the socket back to non-blocking if it was before,
4369 for other operations that support it. */
4370 if (fd_info[fd].flags & FILE_NDELAY)
4371 {
4372 nblock = 1;
4373 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
4374 }
4375
480b0c5b
GV
4376 if (nchars == SOCKET_ERROR)
4377 {
670773af 4378 DebPrint(("sys_write.send failed with error %d on socket %ld\n",
480b0c5b
GV
4379 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
4380 set_errno ();
4381 }
4382 }
4383 else
4384#endif
4385 nchars = _write (fd, buffer, count);
4386
4387 return nchars;
4388}
4389
f52eb3ef
GV
4390static void
4391check_windows_init_file ()
4392{
4393 extern int noninteractive, inhibit_window_system;
4394
4395 /* A common indication that Emacs is not installed properly is when
4396 it cannot find the Windows installation file. If this file does
4397 not exist in the expected place, tell the user. */
4398
177c0ea7 4399 if (!noninteractive && !inhibit_window_system)
d54abccd
GV
4400 {
4401 extern Lisp_Object Vwindow_system, Vload_path, Qfile_exists_p;
a0b9c838 4402 Lisp_Object objs[2];
96ef7d42 4403 Lisp_Object full_load_path;
d54abccd
GV
4404 Lisp_Object init_file;
4405 int fd;
f52eb3ef 4406
a0b9c838
GV
4407 objs[0] = Vload_path;
4408 objs[1] = decode_env_path (0, (getenv ("EMACSLOADPATH")));
4409 full_load_path = Fappend (2, objs);
d54abccd 4410 init_file = build_string ("term/w32-win");
c50a2aa6 4411 fd = openp (full_load_path, init_file, Fget_load_suffixes (), NULL, Qnil);
177c0ea7 4412 if (fd < 0)
d54abccd 4413 {
96ef7d42 4414 Lisp_Object load_path_print = Fprin1_to_string (full_load_path, Qnil);
d5db4077
KR
4415 char *init_file_name = SDATA (init_file);
4416 char *load_path = SDATA (load_path_print);
acc23b87
KS
4417 char *buffer = alloca (1024
4418 + strlen (init_file_name)
4419 + strlen (load_path));
d54abccd 4420
177c0ea7 4421 sprintf (buffer,
d54abccd
GV
4422 "The Emacs Windows initialization file \"%s.el\" "
4423 "could not be found in your Emacs installation. "
4424 "Emacs checked the following directories for this file:\n"
4425 "\n%s\n\n"
4426 "When Emacs cannot find this file, it usually means that it "
4427 "was not installed properly, or its distribution file was "
4428 "not unpacked properly.\nSee the README.W32 file in the "
4429 "top-level Emacs directory for more information.",
4430 init_file_name, load_path);
4431 MessageBox (NULL,
4432 buffer,
4433 "Emacs Abort Dialog",
4434 MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
f52eb3ef
GV
4435 /* Use the low-level Emacs abort. */
4436#undef abort
d54abccd
GV
4437 abort ();
4438 }
4439 else
4440 {
a302c7ae 4441 _close (fd);
d54abccd 4442 }
f52eb3ef 4443 }
f52eb3ef 4444}
480b0c5b
GV
4445
4446void
4447term_ntproc ()
4448{
4449#ifdef HAVE_SOCKETS
4450 /* shutdown the socket interface if necessary */
4451 term_winsock ();
4452#endif
52c7f9ee
JR
4453
4454 term_w32select ();
480b0c5b
GV
4455}
4456
4457void
4458init_ntproc ()
4459{
4460#ifdef HAVE_SOCKETS
f249a012
RS
4461 /* Initialise the socket interface now if available and requested by
4462 the user by defining PRELOAD_WINSOCK; otherwise loading will be
fbd6baed 4463 delayed until open-network-stream is called (w32-has-winsock can
f249a012
RS
4464 also be used to dynamically load or reload winsock).
4465
4466 Conveniently, init_environment is called before us, so
4467 PRELOAD_WINSOCK can be set in the registry. */
4468
4469 /* Always initialize this correctly. */
4470 winsock_lib = NULL;
4471
4472 if (getenv ("PRELOAD_WINSOCK") != NULL)
4473 init_winsock (TRUE);
480b0c5b
GV
4474#endif
4475
4476 /* Initial preparation for subprocess support: replace our standard
4477 handles with non-inheritable versions. */
4478 {
4479 HANDLE parent;
4480 HANDLE stdin_save = INVALID_HANDLE_VALUE;
4481 HANDLE stdout_save = INVALID_HANDLE_VALUE;
4482 HANDLE stderr_save = INVALID_HANDLE_VALUE;
4483
4484 parent = GetCurrentProcess ();
4485
4486 /* ignore errors when duplicating and closing; typically the
4487 handles will be invalid when running as a gui program. */
177c0ea7
JB
4488 DuplicateHandle (parent,
4489 GetStdHandle (STD_INPUT_HANDLE),
480b0c5b 4490 parent,
177c0ea7
JB
4491 &stdin_save,
4492 0,
4493 FALSE,
480b0c5b 4494 DUPLICATE_SAME_ACCESS);
177c0ea7 4495
480b0c5b
GV
4496 DuplicateHandle (parent,
4497 GetStdHandle (STD_OUTPUT_HANDLE),
4498 parent,
4499 &stdout_save,
4500 0,
4501 FALSE,
4502 DUPLICATE_SAME_ACCESS);
177c0ea7 4503
480b0c5b
GV
4504 DuplicateHandle (parent,
4505 GetStdHandle (STD_ERROR_HANDLE),
4506 parent,
4507 &stderr_save,
4508 0,
4509 FALSE,
4510 DUPLICATE_SAME_ACCESS);
177c0ea7 4511
480b0c5b
GV
4512 fclose (stdin);
4513 fclose (stdout);
4514 fclose (stderr);
4515
4516 if (stdin_save != INVALID_HANDLE_VALUE)
4517 _open_osfhandle ((long) stdin_save, O_TEXT);
4518 else
76b3903d
GV
4519 _open ("nul", O_TEXT | O_NOINHERIT | O_RDONLY);
4520 _fdopen (0, "r");
480b0c5b
GV
4521
4522 if (stdout_save != INVALID_HANDLE_VALUE)
4523 _open_osfhandle ((long) stdout_save, O_TEXT);
4524 else
76b3903d
GV
4525 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
4526 _fdopen (1, "w");
480b0c5b
GV
4527
4528 if (stderr_save != INVALID_HANDLE_VALUE)
4529 _open_osfhandle ((long) stderr_save, O_TEXT);
4530 else
76b3903d
GV
4531 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
4532 _fdopen (2, "w");
480b0c5b
GV
4533 }
4534
4535 /* unfortunately, atexit depends on implementation of malloc */
4536 /* atexit (term_ntproc); */
4537 signal (SIGABRT, term_ntproc);
76b3903d
GV
4538
4539 /* determine which drives are fixed, for GetCachedVolumeInformation */
4540 {
4541 /* GetDriveType must have trailing backslash. */
4542 char drive[] = "A:\\";
4543
4544 /* Loop over all possible drive letters */
4545 while (*drive <= 'Z')
4546 {
4547 /* Record if this drive letter refers to a fixed drive. */
177c0ea7 4548 fixed_drives[DRIVE_INDEX (*drive)] =
76b3903d
GV
4549 (GetDriveType (drive) == DRIVE_FIXED);
4550
4551 (*drive)++;
4552 }
a302c7ae
AI
4553
4554 /* Reset the volume info cache. */
4555 volume_cache = NULL;
76b3903d 4556 }
177c0ea7 4557
d54abccd
GV
4558 /* Check to see if Emacs has been installed correctly. */
4559 check_windows_init_file ();
480b0c5b
GV
4560}
4561
a8c3a596
JR
4562/*
4563 shutdown_handler ensures that buffers' autosave files are
4564 up to date when the user logs off, or the system shuts down.
4565*/
4566BOOL WINAPI shutdown_handler(DWORD type)
4567{
4568 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
4569 if (type == CTRL_CLOSE_EVENT /* User closes console window. */
4570 || type == CTRL_LOGOFF_EVENT /* User logs off. */
4571 || type == CTRL_SHUTDOWN_EVENT) /* User shutsdown. */
4572 {
4573 /* Shut down cleanly, making sure autosave files are up to date. */
4574 shut_down_emacs (0, 0, Qnil);
4575 }
4576
7046f191 4577 /* Allow other handlers to handle this signal. */
a8c3a596
JR
4578 return FALSE;
4579}
4580
9785d95b
BK
4581/*
4582 globals_of_w32 is used to initialize those global variables that
4583 must always be initialized on startup even when the global variable
4584 initialized is non zero (see the function main in emacs.c).
4585*/
9bfb11f9
KS
4586void
4587globals_of_w32 ()
9785d95b 4588{
74258518
JR
4589 HMODULE kernel32 = GetModuleHandle ("kernel32.dll");
4590
4591 get_process_times_fn = (GetProcessTimes_Proc)
4592 GetProcAddress (kernel32, "GetProcessTimes");
4593
9785d95b
BK
4594 g_b_init_is_windows_9x = 0;
4595 g_b_init_open_process_token = 0;
4596 g_b_init_get_token_information = 0;
4597 g_b_init_lookup_account_sid = 0;
4598 g_b_init_get_sid_identifier_authority = 0;
9d95a291
EZ
4599 g_b_init_get_sid_sub_authority = 0;
4600 g_b_init_get_sid_sub_authority_count = 0;
8aaaec6b
EZ
4601 g_b_init_get_file_security = 0;
4602 g_b_init_get_security_descriptor_owner = 0;
4603 g_b_init_get_security_descriptor_group = 0;
4604 g_b_init_is_valid_sid = 0;
a8c3a596
JR
4605 /* The following sets a handler for shutdown notifications for
4606 console apps. This actually applies to Emacs in both console and
4607 GUI modes, since we had to fool windows into thinking emacs is a
4608 console application to get console mode to work. */
4609 SetConsoleCtrlHandler(shutdown_handler, TRUE);
8aaaec6b
EZ
4610
4611 /* "None" is the default group name on standalone workstations. */
4612 strcpy (dflt_group_name, "None");
9785d95b
BK
4613}
4614
aa5ee2a3 4615/* end of w32.c */
ab5796a9
MB
4616
4617/* arch-tag: 90442dd3-37be-482b-b272-ac752e3049f1
4618 (do not change this comment) */