* lib-src/ebrowse.c (xfree): Remove definition; s/xfree/free/
[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
1131 if (lpvalue) 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
f332b293 1148 if (lpvalue) 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 {
14c71d8b 1349 if (lpval) 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 }
8aaaec6b
EZ
2965 if (psd)
2966 xfree (psd);
76b3903d
GV
2967
2968#if 0
2969 /* Not sure if there is any point in this. */
2970 if (!NILP (Vw32_generate_fake_inodes))
2971 fake_inode = generate_inode_val (name);
2972 else if (fake_inode == 0)
2973 {
2974 /* For want of something better, try to make everything unique. */
2975 static DWORD gen_num = 0;
2976 fake_inode = ++gen_num;
480b0c5b 2977 }
76b3903d
GV
2978#endif
2979
2980 /* MSVC defines _ino_t to be short; other libc's might not. */
2981 if (sizeof (buf->st_ino) == 2)
2982 buf->st_ino = fake_inode ^ (fake_inode >> 16);
2983 else
2984 buf->st_ino = fake_inode;
480b0c5b 2985
fbd6baed 2986 /* volume_info is set indirectly by map_w32_filename */
480b0c5b
GV
2987 buf->st_dev = volume_info.serialnum;
2988 buf->st_rdev = volume_info.serialnum;
2989
480b0c5b 2990
8aaaec6b
EZ
2991 buf->st_size = wfd.nFileSizeHigh;
2992 buf->st_size <<= 32;
2993 buf->st_size += wfd.nFileSizeLow;
480b0c5b
GV
2994
2995 /* Convert timestamps to Unix format. */
2996 buf->st_mtime = convert_time (wfd.ftLastWriteTime);
2997 buf->st_atime = convert_time (wfd.ftLastAccessTime);
2998 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
2999 buf->st_ctime = convert_time (wfd.ftCreationTime);
3000 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
3001
3002 /* determine rwx permissions */
3003 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
e3b88685 3004 permission = S_IREAD;
480b0c5b 3005 else
e3b88685 3006 permission = S_IREAD | S_IWRITE;
177c0ea7 3007
480b0c5b 3008 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
e3b88685 3009 permission |= S_IEXEC;
b3308d2e 3010 else if (is_exec (name))
e3b88685 3011 permission |= S_IEXEC;
480b0c5b
GV
3012
3013 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
3014
3015 return 0;
3016}
3017
16bb7578
GV
3018/* Provide fstat and utime as well as stat for consistent handling of
3019 file timestamps. */
3020int
3021fstat (int desc, struct stat * buf)
3022{
3023 HANDLE fh = (HANDLE) _get_osfhandle (desc);
3024 BY_HANDLE_FILE_INFORMATION info;
e3b88685 3025 unsigned __int64 fake_inode;
16bb7578
GV
3026 int permission;
3027
3028 switch (GetFileType (fh) & ~FILE_TYPE_REMOTE)
3029 {
3030 case FILE_TYPE_DISK:
e3b88685 3031 buf->st_mode = S_IFREG;
16bb7578
GV
3032 if (!GetFileInformationByHandle (fh, &info))
3033 {
3034 errno = EACCES;
3035 return -1;
3036 }
3037 break;
3038 case FILE_TYPE_PIPE:
e3b88685 3039 buf->st_mode = S_IFIFO;
16bb7578
GV
3040 goto non_disk;
3041 case FILE_TYPE_CHAR:
3042 case FILE_TYPE_UNKNOWN:
3043 default:
e3b88685 3044 buf->st_mode = S_IFCHR;
16bb7578
GV
3045 non_disk:
3046 memset (&info, 0, sizeof (info));
3047 info.dwFileAttributes = 0;
3048 info.ftCreationTime = utc_base_ft;
3049 info.ftLastAccessTime = utc_base_ft;
3050 info.ftLastWriteTime = utc_base_ft;
3051 }
3052
3053 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
e3b88685 3054 buf->st_mode = S_IFDIR;
93e0f0da
JR
3055
3056 buf->st_nlink = info.nNumberOfLinks;
3057 /* Might as well use file index to fake inode values, but this
3058 is not guaranteed to be unique unless we keep a handle open
3059 all the time (even then there are situations where it is
3060 not unique). Reputedly, there are at most 48 bits of info
3061 (on NTFS, presumably less on FAT). */
e3b88685
EZ
3062 fake_inode = info.nFileIndexHigh;
3063 fake_inode <<= 32;
3064 fake_inode += info.nFileIndexLow;
16bb7578
GV
3065
3066 /* MSVC defines _ino_t to be short; other libc's might not. */
3067 if (sizeof (buf->st_ino) == 2)
3068 buf->st_ino = fake_inode ^ (fake_inode >> 16);
3069 else
3070 buf->st_ino = fake_inode;
3071
8aaaec6b
EZ
3072 /* Consider files to belong to current user.
3073 FIXME: this should use GetSecurityInfo API, but it is only
3074 available for _WIN32_WINNT >= 0x501. */
07f7980a
EZ
3075 buf->st_uid = dflt_passwd.pw_uid;
3076 buf->st_gid = dflt_passwd.pw_gid;
8aaaec6b
EZ
3077 strcpy (buf->st_uname, dflt_passwd.pw_name);
3078 strcpy (buf->st_gname, dflt_group.gr_name);
16bb7578
GV
3079
3080 buf->st_dev = info.dwVolumeSerialNumber;
3081 buf->st_rdev = info.dwVolumeSerialNumber;
3082
8aaaec6b
EZ
3083 buf->st_size = info.nFileSizeHigh;
3084 buf->st_size <<= 32;
3085 buf->st_size += info.nFileSizeLow;
16bb7578
GV
3086
3087 /* Convert timestamps to Unix format. */
3088 buf->st_mtime = convert_time (info.ftLastWriteTime);
3089 buf->st_atime = convert_time (info.ftLastAccessTime);
3090 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
3091 buf->st_ctime = convert_time (info.ftCreationTime);
3092 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
3093
3094 /* determine rwx permissions */
3095 if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
e3b88685 3096 permission = S_IREAD;
16bb7578 3097 else
e3b88685 3098 permission = S_IREAD | S_IWRITE;
177c0ea7 3099
16bb7578 3100 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
e3b88685 3101 permission |= S_IEXEC;
16bb7578
GV
3102 else
3103 {
3104#if 0 /* no way of knowing the filename */
3105 char * p = strrchr (name, '.');
3106 if (p != NULL &&
05131107
JR
3107 (xstrcasecmp (p, ".exe") == 0 ||
3108 xstrcasecmp (p, ".com") == 0 ||
3109 xstrcasecmp (p, ".bat") == 0 ||
3110 xstrcasecmp (p, ".cmd") == 0))
e3b88685 3111 permission |= S_IEXEC;
16bb7578
GV
3112#endif
3113 }
3114
3115 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
3116
3117 return 0;
3118}
3119
3120int
3121utime (const char *name, struct utimbuf *times)
3122{
3123 struct utimbuf deftime;
3124 HANDLE fh;
3125 FILETIME mtime;
3126 FILETIME atime;
3127
3128 if (times == NULL)
3129 {
3130 deftime.modtime = deftime.actime = time (NULL);
3131 times = &deftime;
3132 }
3133
3134 /* Need write access to set times. */
3135 fh = CreateFile (name, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
3136 0, OPEN_EXISTING, 0, NULL);
3137 if (fh)
3138 {
3139 convert_from_time_t (times->actime, &atime);
3140 convert_from_time_t (times->modtime, &mtime);
3141 if (!SetFileTime (fh, NULL, &atime, &mtime))
3142 {
3143 CloseHandle (fh);
3144 errno = EACCES;
3145 return -1;
3146 }
3147 CloseHandle (fh);
3148 }
3149 else
3150 {
3151 errno = EINVAL;
3152 return -1;
3153 }
3154 return 0;
3155}
3156
480b0c5b
GV
3157#ifdef HAVE_SOCKETS
3158
3159/* Wrappers for winsock functions to map between our file descriptors
3160 and winsock's handles; also set h_errno for convenience.
3161
3162 To allow Emacs to run on systems which don't have winsock support
3163 installed, we dynamically link to winsock on startup if present, and
3164 otherwise provide the minimum necessary functionality
3165 (eg. gethostname). */
3166
3167/* function pointers for relevant socket functions */
3168int (PASCAL *pfn_WSAStartup) (WORD wVersionRequired, LPWSADATA lpWSAData);
3169void (PASCAL *pfn_WSASetLastError) (int iError);
3170int (PASCAL *pfn_WSAGetLastError) (void);
26fb7bc4 3171int (PASCAL *pfn_WSAEventSelect) (SOCKET s, HANDLE hEventObject, long lNetworkEvents);
64570b36
KS
3172HANDLE (PASCAL *pfn_WSACreateEvent) (void);
3173int (PASCAL *pfn_WSACloseEvent) (HANDLE hEvent);
480b0c5b
GV
3174int (PASCAL *pfn_socket) (int af, int type, int protocol);
3175int (PASCAL *pfn_bind) (SOCKET s, const struct sockaddr *addr, int namelen);
3176int (PASCAL *pfn_connect) (SOCKET s, const struct sockaddr *addr, int namelen);
3177int (PASCAL *pfn_ioctlsocket) (SOCKET s, long cmd, u_long *argp);
3178int (PASCAL *pfn_recv) (SOCKET s, char * buf, int len, int flags);
3179int (PASCAL *pfn_send) (SOCKET s, const char * buf, int len, int flags);
3180int (PASCAL *pfn_closesocket) (SOCKET s);
3181int (PASCAL *pfn_shutdown) (SOCKET s, int how);
3182int (PASCAL *pfn_WSACleanup) (void);
3183
3184u_short (PASCAL *pfn_htons) (u_short hostshort);
3185u_short (PASCAL *pfn_ntohs) (u_short netshort);
3186unsigned long (PASCAL *pfn_inet_addr) (const char * cp);
3187int (PASCAL *pfn_gethostname) (char * name, int namelen);
3188struct hostent * (PASCAL *pfn_gethostbyname) (const char * name);
3189struct servent * (PASCAL *pfn_getservbyname) (const char * name, const char * proto);
ecd270eb 3190int (PASCAL *pfn_getpeername) (SOCKET s, struct sockaddr *addr, int * namelen);
962955c5
JR
3191int (PASCAL *pfn_setsockopt) (SOCKET s, int level, int optname,
3192 const char * optval, int optlen);
3193int (PASCAL *pfn_listen) (SOCKET s, int backlog);
3194int (PASCAL *pfn_getsockname) (SOCKET s, struct sockaddr * name,
3195 int * namelen);
3196SOCKET (PASCAL *pfn_accept) (SOCKET s, struct sockaddr * addr, int * addrlen);
3197int (PASCAL *pfn_recvfrom) (SOCKET s, char * buf, int len, int flags,
3198 struct sockaddr * from, int * fromlen);
3199int (PASCAL *pfn_sendto) (SOCKET s, const char * buf, int len, int flags,
3200 const struct sockaddr * to, int tolen);
3201
f1614061
RS
3202/* SetHandleInformation is only needed to make sockets non-inheritable. */
3203BOOL (WINAPI *pfn_SetHandleInformation) (HANDLE object, DWORD mask, DWORD flags);
3204#ifndef HANDLE_FLAG_INHERIT
3205#define HANDLE_FLAG_INHERIT 1
3206#endif
480b0c5b 3207
f249a012
RS
3208HANDLE winsock_lib;
3209static int winsock_inuse;
480b0c5b 3210
f249a012 3211BOOL
480b0c5b
GV
3212term_winsock (void)
3213{
f249a012 3214 if (winsock_lib != NULL && winsock_inuse == 0)
480b0c5b 3215 {
f249a012
RS
3216 /* Not sure what would cause WSAENETDOWN, or even if it can happen
3217 after WSAStartup returns successfully, but it seems reasonable
3218 to allow unloading winsock anyway in that case. */
3219 if (pfn_WSACleanup () == 0 ||
3220 pfn_WSAGetLastError () == WSAENETDOWN)
3221 {
3222 if (FreeLibrary (winsock_lib))
3223 winsock_lib = NULL;
3224 return TRUE;
3225 }
480b0c5b 3226 }
f249a012 3227 return FALSE;
480b0c5b
GV
3228}
3229
f249a012
RS
3230BOOL
3231init_winsock (int load_now)
480b0c5b
GV
3232{
3233 WSADATA winsockData;
3234
f249a012
RS
3235 if (winsock_lib != NULL)
3236 return TRUE;
f1614061
RS
3237
3238 pfn_SetHandleInformation = NULL;
3239 pfn_SetHandleInformation
3240 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
3241 "SetHandleInformation");
3242
64570b36 3243 winsock_lib = LoadLibrary ("Ws2_32.dll");
480b0c5b
GV
3244
3245 if (winsock_lib != NULL)
3246 {
3247 /* dynamically link to socket functions */
3248
3249#define LOAD_PROC(fn) \
3250 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
3251 goto fail;
3252
3253 LOAD_PROC( WSAStartup );
3254 LOAD_PROC( WSASetLastError );
3255 LOAD_PROC( WSAGetLastError );
26fb7bc4 3256 LOAD_PROC( WSAEventSelect );
64570b36
KS
3257 LOAD_PROC( WSACreateEvent );
3258 LOAD_PROC( WSACloseEvent );
480b0c5b
GV
3259 LOAD_PROC( socket );
3260 LOAD_PROC( bind );
3261 LOAD_PROC( connect );
3262 LOAD_PROC( ioctlsocket );
3263 LOAD_PROC( recv );
3264 LOAD_PROC( send );
3265 LOAD_PROC( closesocket );
3266 LOAD_PROC( shutdown );
3267 LOAD_PROC( htons );
3268 LOAD_PROC( ntohs );
3269 LOAD_PROC( inet_addr );
3270 LOAD_PROC( gethostname );
3271 LOAD_PROC( gethostbyname );
3272 LOAD_PROC( getservbyname );
ecd270eb 3273 LOAD_PROC( getpeername );
480b0c5b 3274 LOAD_PROC( WSACleanup );
962955c5
JR
3275 LOAD_PROC( setsockopt );
3276 LOAD_PROC( listen );
3277 LOAD_PROC( getsockname );
3278 LOAD_PROC( accept );
3279 LOAD_PROC( recvfrom );
3280 LOAD_PROC( sendto );
f249a012
RS
3281#undef LOAD_PROC
3282
480b0c5b
GV
3283 /* specify version 1.1 of winsock */
3284 if (pfn_WSAStartup (0x101, &winsockData) == 0)
3285 {
f249a012
RS
3286 if (winsockData.wVersion != 0x101)
3287 goto fail;
3288
3289 if (!load_now)
3290 {
3291 /* Report that winsock exists and is usable, but leave
3292 socket functions disabled. I am assuming that calling
3293 WSAStartup does not require any network interaction,
3294 and in particular does not cause or require a dial-up
3295 connection to be established. */
3296
3297 pfn_WSACleanup ();
3298 FreeLibrary (winsock_lib);
3299 winsock_lib = NULL;
3300 }
3301 winsock_inuse = 0;
3302 return TRUE;
480b0c5b
GV
3303 }
3304
3305 fail:
3306 FreeLibrary (winsock_lib);
f249a012 3307 winsock_lib = NULL;
480b0c5b 3308 }
f249a012
RS
3309
3310 return FALSE;
480b0c5b
GV
3311}
3312
3313
3314int h_errno = 0;
3315
3316/* function to set h_errno for compatability; map winsock error codes to
3317 normal system codes where they overlap (non-overlapping definitions
3318 are already in <sys/socket.h> */
9bfb11f9
KS
3319static void
3320set_errno ()
480b0c5b 3321{
f249a012 3322 if (winsock_lib == NULL)
480b0c5b
GV
3323 h_errno = EINVAL;
3324 else
3325 h_errno = pfn_WSAGetLastError ();
3326
3327 switch (h_errno)
3328 {
3329 case WSAEACCES: h_errno = EACCES; break;
3330 case WSAEBADF: h_errno = EBADF; break;
3331 case WSAEFAULT: h_errno = EFAULT; break;
3332 case WSAEINTR: h_errno = EINTR; break;
3333 case WSAEINVAL: h_errno = EINVAL; break;
3334 case WSAEMFILE: h_errno = EMFILE; break;
3335 case WSAENAMETOOLONG: h_errno = ENAMETOOLONG; break;
3336 case WSAENOTEMPTY: h_errno = ENOTEMPTY; break;
3337 }
3338 errno = h_errno;
3339}
3340
9bfb11f9
KS
3341static void
3342check_errno ()
480b0c5b 3343{
f249a012 3344 if (h_errno == 0 && winsock_lib != NULL)
480b0c5b
GV
3345 pfn_WSASetLastError (0);
3346}
3347
d8fcc1b9
AI
3348/* Extend strerror to handle the winsock-specific error codes. */
3349struct {
3350 int errnum;
3351 char * msg;
3352} _wsa_errlist[] = {
3353 WSAEINTR , "Interrupted function call",
3354 WSAEBADF , "Bad file descriptor",
3355 WSAEACCES , "Permission denied",
3356 WSAEFAULT , "Bad address",
3357 WSAEINVAL , "Invalid argument",
3358 WSAEMFILE , "Too many open files",
177c0ea7 3359
d8fcc1b9
AI
3360 WSAEWOULDBLOCK , "Resource temporarily unavailable",
3361 WSAEINPROGRESS , "Operation now in progress",
3362 WSAEALREADY , "Operation already in progress",
3363 WSAENOTSOCK , "Socket operation on non-socket",
3364 WSAEDESTADDRREQ , "Destination address required",
3365 WSAEMSGSIZE , "Message too long",
3366 WSAEPROTOTYPE , "Protocol wrong type for socket",
3367 WSAENOPROTOOPT , "Bad protocol option",
3368 WSAEPROTONOSUPPORT , "Protocol not supported",
3369 WSAESOCKTNOSUPPORT , "Socket type not supported",
3370 WSAEOPNOTSUPP , "Operation not supported",
3371 WSAEPFNOSUPPORT , "Protocol family not supported",
3372 WSAEAFNOSUPPORT , "Address family not supported by protocol family",
3373 WSAEADDRINUSE , "Address already in use",
3374 WSAEADDRNOTAVAIL , "Cannot assign requested address",
3375 WSAENETDOWN , "Network is down",
3376 WSAENETUNREACH , "Network is unreachable",
3377 WSAENETRESET , "Network dropped connection on reset",
3378 WSAECONNABORTED , "Software caused connection abort",
3379 WSAECONNRESET , "Connection reset by peer",
3380 WSAENOBUFS , "No buffer space available",
3381 WSAEISCONN , "Socket is already connected",
3382 WSAENOTCONN , "Socket is not connected",
3383 WSAESHUTDOWN , "Cannot send after socket shutdown",
3384 WSAETOOMANYREFS , "Too many references", /* not sure */
3385 WSAETIMEDOUT , "Connection timed out",
3386 WSAECONNREFUSED , "Connection refused",
3387 WSAELOOP , "Network loop", /* not sure */
3388 WSAENAMETOOLONG , "Name is too long",
3389 WSAEHOSTDOWN , "Host is down",
3390 WSAEHOSTUNREACH , "No route to host",
3391 WSAENOTEMPTY , "Buffer not empty", /* not sure */
3392 WSAEPROCLIM , "Too many processes",
3393 WSAEUSERS , "Too many users", /* not sure */
3394 WSAEDQUOT , "Double quote in host name", /* really not sure */
3395 WSAESTALE , "Data is stale", /* not sure */
3396 WSAEREMOTE , "Remote error", /* not sure */
177c0ea7 3397
d8fcc1b9
AI
3398 WSASYSNOTREADY , "Network subsystem is unavailable",
3399 WSAVERNOTSUPPORTED , "WINSOCK.DLL version out of range",
3400 WSANOTINITIALISED , "Winsock not initialized successfully",
3401 WSAEDISCON , "Graceful shutdown in progress",
3402#ifdef WSAENOMORE
3403 WSAENOMORE , "No more operations allowed", /* not sure */
3404 WSAECANCELLED , "Operation cancelled", /* not sure */
3405 WSAEINVALIDPROCTABLE , "Invalid procedure table from service provider",
3406 WSAEINVALIDPROVIDER , "Invalid service provider version number",
3407 WSAEPROVIDERFAILEDINIT , "Unable to initialize a service provider",
aa5ee2a3 3408 WSASYSCALLFAILURE , "System call failure",
d8fcc1b9
AI
3409 WSASERVICE_NOT_FOUND , "Service not found", /* not sure */
3410 WSATYPE_NOT_FOUND , "Class type not found",
3411 WSA_E_NO_MORE , "No more resources available", /* really not sure */
3412 WSA_E_CANCELLED , "Operation already cancelled", /* really not sure */
3413 WSAEREFUSED , "Operation refused", /* not sure */
3414#endif
177c0ea7 3415
d8fcc1b9
AI
3416 WSAHOST_NOT_FOUND , "Host not found",
3417 WSATRY_AGAIN , "Authoritative host not found during name lookup",
3418 WSANO_RECOVERY , "Non-recoverable error during name lookup",
3419 WSANO_DATA , "Valid name, no data record of requested type",
3420
3421 -1, NULL
3422};
3423
3424char *
3425sys_strerror(int error_no)
3426{
3427 int i;
3428 static char unknown_msg[40];
3429
a302c7ae
AI
3430 if (error_no >= 0 && error_no < sys_nerr)
3431 return sys_errlist[error_no];
d8fcc1b9
AI
3432
3433 for (i = 0; _wsa_errlist[i].errnum >= 0; i++)
3434 if (_wsa_errlist[i].errnum == error_no)
3435 return _wsa_errlist[i].msg;
3436
3437 sprintf(unknown_msg, "Unidentified error: %d", error_no);
3438 return unknown_msg;
3439}
3440
480b0c5b
GV
3441/* [andrewi 3-May-96] I've had conflicting results using both methods,
3442 but I believe the method of keeping the socket handle separate (and
3443 insuring it is not inheritable) is the correct one. */
3444
3445//#define SOCK_REPLACE_HANDLE
3446
3447#ifdef SOCK_REPLACE_HANDLE
3448#define SOCK_HANDLE(fd) ((SOCKET) _get_osfhandle (fd))
3449#else
3450#define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
3451#endif
3452
962955c5
JR
3453int socket_to_fd (SOCKET s);
3454
480b0c5b
GV
3455int
3456sys_socket(int af, int type, int protocol)
3457{
962955c5 3458 SOCKET s;
480b0c5b 3459
f249a012 3460 if (winsock_lib == NULL)
480b0c5b
GV
3461 {
3462 h_errno = ENETDOWN;
3463 return INVALID_SOCKET;
3464 }
3465
3466 check_errno ();
3467
3468 /* call the real socket function */
962955c5 3469 s = pfn_socket (af, type, protocol);
177c0ea7 3470
480b0c5b 3471 if (s != INVALID_SOCKET)
962955c5 3472 return socket_to_fd (s);
480b0c5b 3473
962955c5
JR
3474 set_errno ();
3475 return -1;
3476}
3477
3478/* Convert a SOCKET to a file descriptor. */
3479int
3480socket_to_fd (SOCKET s)
3481{
3482 int fd;
3483 child_process * cp;
3484
3485 /* Although under NT 3.5 _open_osfhandle will accept a socket
3486 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
3487 that does not work under NT 3.1. However, we can get the same
3488 effect by using a backdoor function to replace an existing
3489 descriptor handle with the one we want. */
3490
3491 /* allocate a file descriptor (with appropriate flags) */
3492 fd = _open ("NUL:", _O_RDWR);
3493 if (fd >= 0)
3494 {
480b0c5b 3495#ifdef SOCK_REPLACE_HANDLE
962955c5
JR
3496 /* now replace handle to NUL with our socket handle */
3497 CloseHandle ((HANDLE) _get_osfhandle (fd));
3498 _free_osfhnd (fd);
3499 _set_osfhnd (fd, s);
3500 /* setmode (fd, _O_BINARY); */
480b0c5b 3501#else
962955c5
JR
3502 /* Make a non-inheritable copy of the socket handle. Note
3503 that it is possible that sockets aren't actually kernel
3504 handles, which appears to be the case on Windows 9x when
3505 the MS Proxy winsock client is installed. */
3506 {
3507 /* Apparently there is a bug in NT 3.51 with some service
3508 packs, which prevents using DuplicateHandle to make a
3509 socket handle non-inheritable (causes WSACleanup to
3510 hang). The work-around is to use SetHandleInformation
3511 instead if it is available and implemented. */
3512 if (pfn_SetHandleInformation)
480b0c5b 3513 {
962955c5
JR
3514 pfn_SetHandleInformation ((HANDLE) s, HANDLE_FLAG_INHERIT, 0);
3515 }
3516 else
3517 {
3518 HANDLE parent = GetCurrentProcess ();
3519 HANDLE new_s = INVALID_HANDLE_VALUE;
3520
3521 if (DuplicateHandle (parent,
3522 (HANDLE) s,
3523 parent,
3524 &new_s,
3525 0,
3526 FALSE,
3527 DUPLICATE_SAME_ACCESS))
f1614061 3528 {
962955c5
JR
3529 /* It is possible that DuplicateHandle succeeds even
3530 though the socket wasn't really a kernel handle,
3531 because a real handle has the same value. So
3532 test whether the new handle really is a socket. */
3533 long nonblocking = 0;
3534 if (pfn_ioctlsocket ((SOCKET) new_s, FIONBIO, &nonblocking) == 0)
ca149beb 3535 {
962955c5
JR
3536 pfn_closesocket (s);
3537 s = (SOCKET) new_s;
3538 }
3539 else
3540 {
3541 CloseHandle (new_s);
3542 }
177c0ea7 3543 }
480b0c5b 3544 }
962955c5
JR
3545 }
3546 fd_info[fd].hnd = (HANDLE) s;
480b0c5b
GV
3547#endif
3548
962955c5
JR
3549 /* set our own internal flags */
3550 fd_info[fd].flags = FILE_SOCKET | FILE_BINARY | FILE_READ | FILE_WRITE;
480b0c5b 3551
962955c5
JR
3552 cp = new_child ();
3553 if (cp)
3554 {
3555 cp->fd = fd;
3556 cp->status = STATUS_READ_ACKNOWLEDGED;
480b0c5b 3557
962955c5
JR
3558 /* attach child_process to fd_info */
3559 if (fd_info[ fd ].cp != NULL)
3560 {
3561 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd));
3562 abort ();
480b0c5b
GV
3563 }
3564
962955c5
JR
3565 fd_info[ fd ].cp = cp;
3566
3567 /* success! */
3568 winsock_inuse++; /* count open sockets */
3569 return fd;
480b0c5b 3570 }
480b0c5b 3571
962955c5
JR
3572 /* clean up */
3573 _close (fd);
3574 }
3575 pfn_closesocket (s);
3576 h_errno = EMFILE;
480b0c5b
GV
3577 return -1;
3578}
3579
3580
3581int
3582sys_bind (int s, const struct sockaddr * addr, int namelen)
3583{
f249a012 3584 if (winsock_lib == NULL)
480b0c5b
GV
3585 {
3586 h_errno = ENOTSOCK;
3587 return SOCKET_ERROR;
3588 }
3589
3590 check_errno ();
3591 if (fd_info[s].flags & FILE_SOCKET)
3592 {
3593 int rc = pfn_bind (SOCK_HANDLE (s), addr, namelen);
3594 if (rc == SOCKET_ERROR)
3595 set_errno ();
3596 return rc;
3597 }
3598 h_errno = ENOTSOCK;
3599 return SOCKET_ERROR;
3600}
3601
3602
3603int
3604sys_connect (int s, const struct sockaddr * name, int namelen)
3605{
f249a012 3606 if (winsock_lib == NULL)
480b0c5b
GV
3607 {
3608 h_errno = ENOTSOCK;
3609 return SOCKET_ERROR;
3610 }
3611
3612 check_errno ();
3613 if (fd_info[s].flags & FILE_SOCKET)
3614 {
3615 int rc = pfn_connect (SOCK_HANDLE (s), name, namelen);
3616 if (rc == SOCKET_ERROR)
3617 set_errno ();
3618 return rc;
3619 }
3620 h_errno = ENOTSOCK;
3621 return SOCKET_ERROR;
3622}
3623
3624u_short
3625sys_htons (u_short hostshort)
3626{
f249a012 3627 return (winsock_lib != NULL) ?
480b0c5b
GV
3628 pfn_htons (hostshort) : hostshort;
3629}
3630
3631u_short
3632sys_ntohs (u_short netshort)
3633{
f249a012 3634 return (winsock_lib != NULL) ?
480b0c5b
GV
3635 pfn_ntohs (netshort) : netshort;
3636}
3637
3638unsigned long
3639sys_inet_addr (const char * cp)
3640{
f249a012 3641 return (winsock_lib != NULL) ?
480b0c5b
GV
3642 pfn_inet_addr (cp) : INADDR_NONE;
3643}
3644
3645int
3646sys_gethostname (char * name, int namelen)
3647{
f249a012 3648 if (winsock_lib != NULL)
480b0c5b
GV
3649 return pfn_gethostname (name, namelen);
3650
3651 if (namelen > MAX_COMPUTERNAME_LENGTH)
a302c7ae 3652 return !GetComputerName (name, (DWORD *)&namelen);
480b0c5b
GV
3653
3654 h_errno = EFAULT;
3655 return SOCKET_ERROR;
3656}
3657
3658struct hostent *
3659sys_gethostbyname(const char * name)
3660{
3661 struct hostent * host;
3662
f249a012 3663 if (winsock_lib == NULL)
480b0c5b
GV
3664 {
3665 h_errno = ENETDOWN;
3666 return NULL;
3667 }
3668
3669 check_errno ();
3670 host = pfn_gethostbyname (name);
3671 if (!host)
3672 set_errno ();
3673 return host;
3674}
3675
3676struct servent *
3677sys_getservbyname(const char * name, const char * proto)
3678{
3679 struct servent * serv;
3680
f249a012 3681 if (winsock_lib == NULL)
480b0c5b
GV
3682 {
3683 h_errno = ENETDOWN;
3684 return NULL;
3685 }
3686
3687 check_errno ();
3688 serv = pfn_getservbyname (name, proto);
3689 if (!serv)
3690 set_errno ();
3691 return serv;
3692}
3693
ecd270eb
JR
3694int
3695sys_getpeername (int s, struct sockaddr *addr, int * namelen)
3696{
3697 if (winsock_lib == NULL)
3698 {
3699 h_errno = ENETDOWN;
3700 return SOCKET_ERROR;
3701 }
3702
3703 check_errno ();
3704 if (fd_info[s].flags & FILE_SOCKET)
3705 {
3706 int rc = pfn_getpeername (SOCK_HANDLE (s), addr, namelen);
3707 if (rc == SOCKET_ERROR)
3708 set_errno ();
3709 return rc;
3710 }
3711 h_errno = ENOTSOCK;
3712 return SOCKET_ERROR;
3713}
3714
3715
380961a6
GV
3716int
3717sys_shutdown (int s, int how)
3718{
380961a6
GV
3719 if (winsock_lib == NULL)
3720 {
3721 h_errno = ENETDOWN;
3722 return SOCKET_ERROR;
3723 }
3724
3725 check_errno ();
3726 if (fd_info[s].flags & FILE_SOCKET)
3727 {
3728 int rc = pfn_shutdown (SOCK_HANDLE (s), how);
962955c5
JR
3729 if (rc == SOCKET_ERROR)
3730 set_errno ();
3731 return rc;
3732 }
3733 h_errno = ENOTSOCK;
3734 return SOCKET_ERROR;
3735}
3736
3737int
a5a389bb 3738sys_setsockopt (int s, int level, int optname, const void * optval, int optlen)
962955c5
JR
3739{
3740 if (winsock_lib == NULL)
3741 {
3742 h_errno = ENETDOWN;
3743 return SOCKET_ERROR;
3744 }
3745
3746 check_errno ();
3747 if (fd_info[s].flags & FILE_SOCKET)
3748 {
3749 int rc = pfn_setsockopt (SOCK_HANDLE (s), level, optname,
a5a389bb 3750 (const char *)optval, optlen);
962955c5
JR
3751 if (rc == SOCKET_ERROR)
3752 set_errno ();
3753 return rc;
3754 }
3755 h_errno = ENOTSOCK;
177c0ea7 3756 return SOCKET_ERROR;
962955c5
JR
3757}
3758
3759int
3760sys_listen (int s, int backlog)
3761{
3762 if (winsock_lib == NULL)
3763 {
3764 h_errno = ENETDOWN;
3765 return SOCKET_ERROR;
3766 }
3767
3768 check_errno ();
3769 if (fd_info[s].flags & FILE_SOCKET)
3770 {
3771 int rc = pfn_listen (SOCK_HANDLE (s), backlog);
3772 if (rc == SOCKET_ERROR)
3773 set_errno ();
26fb7bc4 3774 else
64570b36 3775 fd_info[s].flags |= FILE_LISTEN;
962955c5
JR
3776 return rc;
3777 }
3778 h_errno = ENOTSOCK;
177c0ea7 3779 return SOCKET_ERROR;
962955c5
JR
3780}
3781
3782int
3783sys_getsockname (int s, struct sockaddr * name, int * namelen)
3784{
3785 if (winsock_lib == NULL)
3786 {
3787 h_errno = ENETDOWN;
3788 return SOCKET_ERROR;
3789 }
3790
3791 check_errno ();
3792 if (fd_info[s].flags & FILE_SOCKET)
3793 {
3794 int rc = pfn_getsockname (SOCK_HANDLE (s), name, namelen);
3795 if (rc == SOCKET_ERROR)
3796 set_errno ();
3797 return rc;
3798 }
3799 h_errno = ENOTSOCK;
177c0ea7 3800 return SOCKET_ERROR;
962955c5
JR
3801}
3802
3803int
3804sys_accept (int s, struct sockaddr * addr, int * addrlen)
3805{
3806 if (winsock_lib == NULL)
3807 {
3808 h_errno = ENETDOWN;
3809 return -1;
3810 }
3811
3812 check_errno ();
26fb7bc4 3813 if (fd_info[s].flags & FILE_LISTEN)
962955c5 3814 {
a0ad1860 3815 SOCKET t = pfn_accept (SOCK_HANDLE (s), addr, addrlen);
64570b36
KS
3816 int fd = -1;
3817 if (t == INVALID_SOCKET)
3818 set_errno ();
3819 else
3820 fd = socket_to_fd (t);
962955c5 3821
64570b36
KS
3822 fd_info[s].cp->status = STATUS_READ_ACKNOWLEDGED;
3823 ResetEvent (fd_info[s].cp->char_avail);
3824 return fd;
962955c5
JR
3825 }
3826 h_errno = ENOTSOCK;
3827 return -1;
3828}
3829
3830int
3831sys_recvfrom (int s, char * buf, int len, int flags,
3832 struct sockaddr * from, int * fromlen)
3833{
3834 if (winsock_lib == NULL)
3835 {
3836 h_errno = ENETDOWN;
3837 return SOCKET_ERROR;
3838 }
3839
3840 check_errno ();
3841 if (fd_info[s].flags & FILE_SOCKET)
3842 {
3843 int rc = pfn_recvfrom (SOCK_HANDLE (s), buf, len, flags, from, fromlen);
3844 if (rc == SOCKET_ERROR)
3845 set_errno ();
3846 return rc;
3847 }
3848 h_errno = ENOTSOCK;
3849 return SOCKET_ERROR;
3850}
3851
3852int
3853sys_sendto (int s, const char * buf, int len, int flags,
3854 const struct sockaddr * to, int tolen)
3855{
3856 if (winsock_lib == NULL)
3857 {
3858 h_errno = ENETDOWN;
3859 return SOCKET_ERROR;
3860 }
3861
3862 check_errno ();
3863 if (fd_info[s].flags & FILE_SOCKET)
3864 {
3865 int rc = pfn_sendto (SOCK_HANDLE (s), buf, len, flags, to, tolen);
380961a6
GV
3866 if (rc == SOCKET_ERROR)
3867 set_errno ();
3868 return rc;
3869 }
3870 h_errno = ENOTSOCK;
3871 return SOCKET_ERROR;
3872}
3873
ecd270eb
JR
3874/* Windows does not have an fcntl function. Provide an implementation
3875 solely for making sockets non-blocking. */
3876int
3877fcntl (int s, int cmd, int options)
3878{
3879 if (winsock_lib == NULL)
3880 {
3881 h_errno = ENETDOWN;
3882 return -1;
3883 }
3884
3885 check_errno ();
3886 if (fd_info[s].flags & FILE_SOCKET)
3887 {
3888 if (cmd == F_SETFL && options == O_NDELAY)
3889 {
3890 unsigned long nblock = 1;
3891 int rc = pfn_ioctlsocket (SOCK_HANDLE (s), FIONBIO, &nblock);
3892 if (rc == SOCKET_ERROR)
3893 set_errno();
3894 /* Keep track of the fact that we set this to non-blocking. */
3895 fd_info[s].flags |= FILE_NDELAY;
3896 return rc;
3897 }
3898 else
3899 {
3900 h_errno = EINVAL;
3901 return SOCKET_ERROR;
3902 }
3903 }
3904 h_errno = ENOTSOCK;
3905 return SOCKET_ERROR;
3906}
3907
480b0c5b
GV
3908#endif /* HAVE_SOCKETS */
3909
3910
3911/* Shadow main io functions: we need to handle pipes and sockets more
3912 intelligently, and implement non-blocking mode as well. */
3913
3914int
3915sys_close (int fd)
3916{
3917 int rc;
3918
7559f399 3919 if (fd < 0)
480b0c5b
GV
3920 {
3921 errno = EBADF;
3922 return -1;
3923 }
3924
7559f399 3925 if (fd < MAXDESC && fd_info[fd].cp)
480b0c5b
GV
3926 {
3927 child_process * cp = fd_info[fd].cp;
3928
3929 fd_info[fd].cp = NULL;
3930
3931 if (CHILD_ACTIVE (cp))
3932 {
3933 /* if last descriptor to active child_process then cleanup */
3934 int i;
3935 for (i = 0; i < MAXDESC; i++)
3936 {
3937 if (i == fd)
3938 continue;
3939 if (fd_info[i].cp == cp)
3940 break;
3941 }
3942 if (i == MAXDESC)
3943 {
f249a012 3944#ifdef HAVE_SOCKETS
480b0c5b
GV
3945 if (fd_info[fd].flags & FILE_SOCKET)
3946 {
f249a012
RS
3947#ifndef SOCK_REPLACE_HANDLE
3948 if (winsock_lib == NULL) abort ();
480b0c5b
GV
3949
3950 pfn_shutdown (SOCK_HANDLE (fd), 2);
3951 rc = pfn_closesocket (SOCK_HANDLE (fd));
f249a012
RS
3952#endif
3953 winsock_inuse--; /* count open sockets */
480b0c5b
GV
3954 }
3955#endif
3956 delete_child (cp);
3957 }
3958 }
3959 }
3960
3961 /* Note that sockets do not need special treatment here (at least on
e9e23e23 3962 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
480b0c5b
GV
3963 closesocket is equivalent to CloseHandle, which is to be expected
3964 because socket handles are fully fledged kernel handles. */
3965 rc = _close (fd);
3966
7559f399 3967 if (rc == 0 && fd < MAXDESC)
480b0c5b
GV
3968 fd_info[fd].flags = 0;
3969
3970 return rc;
3971}
3972
3973int
3974sys_dup (int fd)
3975{
3976 int new_fd;
3977
3978 new_fd = _dup (fd);
7559f399 3979 if (new_fd >= 0 && new_fd < MAXDESC)
480b0c5b
GV
3980 {
3981 /* duplicate our internal info as well */
3982 fd_info[new_fd] = fd_info[fd];
3983 }
3984 return new_fd;
3985}
3986
3987
3988int
3989sys_dup2 (int src, int dst)
3990{
3991 int rc;
3992
3993 if (dst < 0 || dst >= MAXDESC)
3994 {
3995 errno = EBADF;
3996 return -1;
3997 }
3998
3999 /* make sure we close the destination first if it's a pipe or socket */
4000 if (src != dst && fd_info[dst].flags != 0)
4001 sys_close (dst);
177c0ea7 4002
480b0c5b
GV
4003 rc = _dup2 (src, dst);
4004 if (rc == 0)
4005 {
4006 /* duplicate our internal info as well */
4007 fd_info[dst] = fd_info[src];
4008 }
4009 return rc;
4010}
4011
480b0c5b
GV
4012/* Unix pipe() has only one arg */
4013int
4014sys_pipe (int * phandles)
4015{
4016 int rc;
4017 unsigned flags;
480b0c5b 4018
76b3903d
GV
4019 /* make pipe handles non-inheritable; when we spawn a child, we
4020 replace the relevant handle with an inheritable one. Also put
4021 pipes into binary mode; we will do text mode translation ourselves
4022 if required. */
4023 rc = _pipe (phandles, 0, _O_NOINHERIT | _O_BINARY);
480b0c5b
GV
4024
4025 if (rc == 0)
4026 {
cb72110d
JR
4027 /* Protect against overflow, since Windows can open more handles than
4028 our fd_info array has room for. */
4029 if (phandles[0] >= MAXDESC || phandles[1] >= MAXDESC)
4030 {
4031 _close (phandles[0]);
4032 _close (phandles[1]);
4033 rc = -1;
4034 }
4035 else
4036 {
4037 flags = FILE_PIPE | FILE_READ | FILE_BINARY;
4038 fd_info[phandles[0]].flags = flags;
480b0c5b 4039
cb72110d
JR
4040 flags = FILE_PIPE | FILE_WRITE | FILE_BINARY;
4041 fd_info[phandles[1]].flags = flags;
4042 }
480b0c5b
GV
4043 }
4044
4045 return rc;
4046}
4047
f7554349 4048/* From ntproc.c */
78806724 4049extern int w32_pipe_read_delay;
f7554349 4050
480b0c5b
GV
4051/* Function to do blocking read of one byte, needed to implement
4052 select. It is only allowed on sockets and pipes. */
4053int
4054_sys_read_ahead (int fd)
4055{
4056 child_process * cp;
4057 int rc;
4058
4059 if (fd < 0 || fd >= MAXDESC)
4060 return STATUS_READ_ERROR;
4061
4062 cp = fd_info[fd].cp;
4063
4064 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
4065 return STATUS_READ_ERROR;
4066
4067 if ((fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET)) == 0
4068 || (fd_info[fd].flags & FILE_READ) == 0)
4069 {
4070 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe or socket!\n", fd));
4071 abort ();
4072 }
177c0ea7 4073
480b0c5b 4074 cp->status = STATUS_READ_IN_PROGRESS;
177c0ea7 4075
480b0c5b 4076 if (fd_info[fd].flags & FILE_PIPE)
f7554349 4077 {
f7554349
KH
4078 rc = _read (fd, &cp->chr, sizeof (char));
4079
4080 /* Give subprocess time to buffer some more output for us before
e9e23e23 4081 reporting that input is available; we need this because Windows 95
f7554349
KH
4082 connects DOS programs to pipes by making the pipe appear to be
4083 the normal console stdout - as a result most DOS programs will
4084 write to stdout without buffering, ie. one character at a
fbd6baed 4085 time. Even some W32 programs do this - "dir" in a command
f7554349
KH
4086 shell on NT is very slow if we don't do this. */
4087 if (rc > 0)
4088 {
78806724 4089 int wait = w32_pipe_read_delay;
f7554349
KH
4090
4091 if (wait > 0)
4092 Sleep (wait);
4093 else if (wait < 0)
4094 while (++wait <= 0)
4095 /* Yield remainder of our time slice, effectively giving a
4096 temporary priority boost to the child process. */
4097 Sleep (0);
4098 }
4099 }
480b0c5b
GV
4100#ifdef HAVE_SOCKETS
4101 else if (fd_info[fd].flags & FILE_SOCKET)
ecd270eb
JR
4102 {
4103 unsigned long nblock = 0;
4104 /* We always want this to block, so temporarily disable NDELAY. */
4105 if (fd_info[fd].flags & FILE_NDELAY)
4106 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
4107
4108 rc = pfn_recv (SOCK_HANDLE (fd), &cp->chr, sizeof (char), 0);
4109
4110 if (fd_info[fd].flags & FILE_NDELAY)
4111 {
4112 nblock = 1;
4113 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
4114 }
4115 }
480b0c5b 4116#endif
177c0ea7 4117
480b0c5b
GV
4118 if (rc == sizeof (char))
4119 cp->status = STATUS_READ_SUCCEEDED;
4120 else
4121 cp->status = STATUS_READ_FAILED;
4122
4123 return cp->status;
4124}
4125
9bfb11f9
KS
4126int
4127_sys_wait_accept (int fd)
64570b36
KS
4128{
4129 HANDLE hEv;
4130 child_process * cp;
4131 int rc;
4132
4133 if (fd < 0 || fd >= MAXDESC)
4134 return STATUS_READ_ERROR;
4135
4136 cp = fd_info[fd].cp;
4137
4138 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
4139 return STATUS_READ_ERROR;
4140
4141 cp->status = STATUS_READ_FAILED;
4142
4143 hEv = pfn_WSACreateEvent ();
4144 rc = pfn_WSAEventSelect (SOCK_HANDLE (fd), hEv, FD_ACCEPT);
4145 if (rc != SOCKET_ERROR)
4146 {
4147 rc = WaitForSingleObject (hEv, INFINITE);
4148 pfn_WSAEventSelect (SOCK_HANDLE (fd), NULL, 0);
64570b36
KS
4149 if (rc == WAIT_OBJECT_0)
4150 cp->status = STATUS_READ_SUCCEEDED;
4151 }
7046f191 4152 pfn_WSACloseEvent (hEv);
64570b36
KS
4153
4154 return cp->status;
4155}
4156
480b0c5b
GV
4157int
4158sys_read (int fd, char * buffer, unsigned int count)
4159{
4160 int nchars;
480b0c5b
GV
4161 int to_read;
4162 DWORD waiting;
76b3903d 4163 char * orig_buffer = buffer;
480b0c5b 4164
7559f399 4165 if (fd < 0)
480b0c5b
GV
4166 {
4167 errno = EBADF;
4168 return -1;
4169 }
4170
7559f399 4171 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET))
480b0c5b
GV
4172 {
4173 child_process *cp = fd_info[fd].cp;
4174
4175 if ((fd_info[fd].flags & FILE_READ) == 0)
4176 {
4177 errno = EBADF;
4178 return -1;
4179 }
4180
76b3903d
GV
4181 nchars = 0;
4182
4183 /* re-read CR carried over from last read */
4184 if (fd_info[fd].flags & FILE_LAST_CR)
4185 {
4186 if (fd_info[fd].flags & FILE_BINARY) abort ();
4187 *buffer++ = 0x0d;
4188 count--;
4189 nchars++;
f52eb3ef 4190 fd_info[fd].flags &= ~FILE_LAST_CR;
76b3903d
GV
4191 }
4192
480b0c5b
GV
4193 /* presence of a child_process structure means we are operating in
4194 non-blocking mode - otherwise we just call _read directly.
4195 Note that the child_process structure might be missing because
4196 reap_subprocess has been called; in this case the pipe is
4197 already broken, so calling _read on it is okay. */
4198 if (cp)
4199 {
4200 int current_status = cp->status;
4201
4202 switch (current_status)
4203 {
4204 case STATUS_READ_FAILED:
4205 case STATUS_READ_ERROR:
f52eb3ef
GV
4206 /* report normal EOF if nothing in buffer */
4207 if (nchars <= 0)
4208 fd_info[fd].flags |= FILE_AT_EOF;
4209 return nchars;
480b0c5b
GV
4210
4211 case STATUS_READ_READY:
4212 case STATUS_READ_IN_PROGRESS:
4213 DebPrint (("sys_read called when read is in progress\n"));
4214 errno = EWOULDBLOCK;
4215 return -1;
4216
4217 case STATUS_READ_SUCCEEDED:
4218 /* consume read-ahead char */
4219 *buffer++ = cp->chr;
4220 count--;
76b3903d 4221 nchars++;
480b0c5b
GV
4222 cp->status = STATUS_READ_ACKNOWLEDGED;
4223 ResetEvent (cp->char_avail);
4224
4225 case STATUS_READ_ACKNOWLEDGED:
4226 break;
4227
4228 default:
4229 DebPrint (("sys_read: bad status %d\n", current_status));
4230 errno = EBADF;
4231 return -1;
4232 }
4233
4234 if (fd_info[fd].flags & FILE_PIPE)
4235 {
4236 PeekNamedPipe ((HANDLE) _get_osfhandle (fd), NULL, 0, NULL, &waiting, NULL);
4237 to_read = min (waiting, (DWORD) count);
f52eb3ef
GV
4238
4239 if (to_read > 0)
4240 nchars += _read (fd, buffer, to_read);
480b0c5b
GV
4241 }
4242#ifdef HAVE_SOCKETS
4243 else /* FILE_SOCKET */
4244 {
f249a012 4245 if (winsock_lib == NULL) abort ();
480b0c5b
GV
4246
4247 /* do the equivalent of a non-blocking read */
4248 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONREAD, &waiting);
76b3903d 4249 if (waiting == 0 && nchars == 0)
480b0c5b
GV
4250 {
4251 h_errno = errno = EWOULDBLOCK;
4252 return -1;
4253 }
4254
480b0c5b
GV
4255 if (waiting)
4256 {
4257 /* always use binary mode for sockets */
76b3903d
GV
4258 int res = pfn_recv (SOCK_HANDLE (fd), buffer, count, 0);
4259 if (res == SOCKET_ERROR)
480b0c5b
GV
4260 {
4261 DebPrint(("sys_read.recv failed with error %d on socket %ld\n",
4262 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
76b3903d
GV
4263 set_errno ();
4264 return -1;
480b0c5b 4265 }
76b3903d 4266 nchars += res;
480b0c5b
GV
4267 }
4268 }
4269#endif
4270 }
4271 else
f52eb3ef
GV
4272 {
4273 int nread = _read (fd, buffer, count);
4274 if (nread >= 0)
4275 nchars += nread;
4276 else if (nchars == 0)
4277 nchars = nread;
4278 }
76b3903d 4279
f52eb3ef
GV
4280 if (nchars <= 0)
4281 fd_info[fd].flags |= FILE_AT_EOF;
76b3903d 4282 /* Perform text mode translation if required. */
f52eb3ef 4283 else if ((fd_info[fd].flags & FILE_BINARY) == 0)
76b3903d
GV
4284 {
4285 nchars = crlf_to_lf (nchars, orig_buffer);
4286 /* If buffer contains only CR, return that. To be absolutely
4287 sure we should attempt to read the next char, but in
4288 practice a CR to be followed by LF would not appear by
4289 itself in the buffer. */
4290 if (nchars > 1 && orig_buffer[nchars - 1] == 0x0d)
4291 {
4292 fd_info[fd].flags |= FILE_LAST_CR;
4293 nchars--;
4294 }
76b3903d 4295 }
480b0c5b
GV
4296 }
4297 else
4298 nchars = _read (fd, buffer, count);
4299
76b3903d 4300 return nchars;
480b0c5b
GV
4301}
4302
4303/* For now, don't bother with a non-blocking mode */
4304int
4305sys_write (int fd, const void * buffer, unsigned int count)
4306{
4307 int nchars;
4308
7559f399 4309 if (fd < 0)
480b0c5b
GV
4310 {
4311 errno = EBADF;
4312 return -1;
4313 }
4314
7559f399 4315 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET))
76b3903d
GV
4316 {
4317 if ((fd_info[fd].flags & FILE_WRITE) == 0)
4318 {
4319 errno = EBADF;
4320 return -1;
4321 }
4322
4323 /* Perform text mode translation if required. */
4324 if ((fd_info[fd].flags & FILE_BINARY) == 0)
4325 {
4326 char * tmpbuf = alloca (count * 2);
4327 unsigned char * src = (void *)buffer;
4328 unsigned char * dst = tmpbuf;
4329 int nbytes = count;
4330
4331 while (1)
4332 {
4333 unsigned char *next;
4334 /* copy next line or remaining bytes */
4335 next = _memccpy (dst, src, '\n', nbytes);
4336 if (next)
4337 {
4338 /* copied one line ending with '\n' */
4339 int copied = next - dst;
4340 nbytes -= copied;
4341 src += copied;
4342 /* insert '\r' before '\n' */
4343 next[-1] = '\r';
4344 next[0] = '\n';
4345 dst = next + 1;
4346 count++;
177c0ea7 4347 }
76b3903d
GV
4348 else
4349 /* copied remaining partial line -> now finished */
4350 break;
4351 }
4352 buffer = tmpbuf;
4353 }
4354 }
4355
480b0c5b 4356#ifdef HAVE_SOCKETS
7559f399 4357 if (fd < MAXDESC && fd_info[fd].flags & FILE_SOCKET)
480b0c5b 4358 {
30a32e0e 4359 unsigned long nblock = 0;
f249a012 4360 if (winsock_lib == NULL) abort ();
30a32e0e
JR
4361
4362 /* TODO: implement select() properly so non-blocking I/O works. */
4363 /* For now, make sure the write blocks. */
4364 if (fd_info[fd].flags & FILE_NDELAY)
4365 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
4366
480b0c5b 4367 nchars = pfn_send (SOCK_HANDLE (fd), buffer, count, 0);
30a32e0e
JR
4368
4369 /* Set the socket back to non-blocking if it was before,
4370 for other operations that support it. */
4371 if (fd_info[fd].flags & FILE_NDELAY)
4372 {
4373 nblock = 1;
4374 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
4375 }
4376
480b0c5b
GV
4377 if (nchars == SOCKET_ERROR)
4378 {
670773af 4379 DebPrint(("sys_write.send failed with error %d on socket %ld\n",
480b0c5b
GV
4380 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
4381 set_errno ();
4382 }
4383 }
4384 else
4385#endif
4386 nchars = _write (fd, buffer, count);
4387
4388 return nchars;
4389}
4390
f52eb3ef
GV
4391static void
4392check_windows_init_file ()
4393{
4394 extern int noninteractive, inhibit_window_system;
4395
4396 /* A common indication that Emacs is not installed properly is when
4397 it cannot find the Windows installation file. If this file does
4398 not exist in the expected place, tell the user. */
4399
177c0ea7 4400 if (!noninteractive && !inhibit_window_system)
d54abccd
GV
4401 {
4402 extern Lisp_Object Vwindow_system, Vload_path, Qfile_exists_p;
a0b9c838 4403 Lisp_Object objs[2];
96ef7d42 4404 Lisp_Object full_load_path;
d54abccd
GV
4405 Lisp_Object init_file;
4406 int fd;
f52eb3ef 4407
a0b9c838
GV
4408 objs[0] = Vload_path;
4409 objs[1] = decode_env_path (0, (getenv ("EMACSLOADPATH")));
4410 full_load_path = Fappend (2, objs);
d54abccd 4411 init_file = build_string ("term/w32-win");
c50a2aa6 4412 fd = openp (full_load_path, init_file, Fget_load_suffixes (), NULL, Qnil);
177c0ea7 4413 if (fd < 0)
d54abccd 4414 {
96ef7d42 4415 Lisp_Object load_path_print = Fprin1_to_string (full_load_path, Qnil);
d5db4077
KR
4416 char *init_file_name = SDATA (init_file);
4417 char *load_path = SDATA (load_path_print);
acc23b87
KS
4418 char *buffer = alloca (1024
4419 + strlen (init_file_name)
4420 + strlen (load_path));
d54abccd 4421
177c0ea7 4422 sprintf (buffer,
d54abccd
GV
4423 "The Emacs Windows initialization file \"%s.el\" "
4424 "could not be found in your Emacs installation. "
4425 "Emacs checked the following directories for this file:\n"
4426 "\n%s\n\n"
4427 "When Emacs cannot find this file, it usually means that it "
4428 "was not installed properly, or its distribution file was "
4429 "not unpacked properly.\nSee the README.W32 file in the "
4430 "top-level Emacs directory for more information.",
4431 init_file_name, load_path);
4432 MessageBox (NULL,
4433 buffer,
4434 "Emacs Abort Dialog",
4435 MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
f52eb3ef
GV
4436 /* Use the low-level Emacs abort. */
4437#undef abort
d54abccd
GV
4438 abort ();
4439 }
4440 else
4441 {
a302c7ae 4442 _close (fd);
d54abccd 4443 }
f52eb3ef 4444 }
f52eb3ef 4445}
480b0c5b
GV
4446
4447void
4448term_ntproc ()
4449{
4450#ifdef HAVE_SOCKETS
4451 /* shutdown the socket interface if necessary */
4452 term_winsock ();
4453#endif
52c7f9ee
JR
4454
4455 term_w32select ();
480b0c5b
GV
4456}
4457
4458void
4459init_ntproc ()
4460{
4461#ifdef HAVE_SOCKETS
f249a012
RS
4462 /* Initialise the socket interface now if available and requested by
4463 the user by defining PRELOAD_WINSOCK; otherwise loading will be
fbd6baed 4464 delayed until open-network-stream is called (w32-has-winsock can
f249a012
RS
4465 also be used to dynamically load or reload winsock).
4466
4467 Conveniently, init_environment is called before us, so
4468 PRELOAD_WINSOCK can be set in the registry. */
4469
4470 /* Always initialize this correctly. */
4471 winsock_lib = NULL;
4472
4473 if (getenv ("PRELOAD_WINSOCK") != NULL)
4474 init_winsock (TRUE);
480b0c5b
GV
4475#endif
4476
4477 /* Initial preparation for subprocess support: replace our standard
4478 handles with non-inheritable versions. */
4479 {
4480 HANDLE parent;
4481 HANDLE stdin_save = INVALID_HANDLE_VALUE;
4482 HANDLE stdout_save = INVALID_HANDLE_VALUE;
4483 HANDLE stderr_save = INVALID_HANDLE_VALUE;
4484
4485 parent = GetCurrentProcess ();
4486
4487 /* ignore errors when duplicating and closing; typically the
4488 handles will be invalid when running as a gui program. */
177c0ea7
JB
4489 DuplicateHandle (parent,
4490 GetStdHandle (STD_INPUT_HANDLE),
480b0c5b 4491 parent,
177c0ea7
JB
4492 &stdin_save,
4493 0,
4494 FALSE,
480b0c5b 4495 DUPLICATE_SAME_ACCESS);
177c0ea7 4496
480b0c5b
GV
4497 DuplicateHandle (parent,
4498 GetStdHandle (STD_OUTPUT_HANDLE),
4499 parent,
4500 &stdout_save,
4501 0,
4502 FALSE,
4503 DUPLICATE_SAME_ACCESS);
177c0ea7 4504
480b0c5b
GV
4505 DuplicateHandle (parent,
4506 GetStdHandle (STD_ERROR_HANDLE),
4507 parent,
4508 &stderr_save,
4509 0,
4510 FALSE,
4511 DUPLICATE_SAME_ACCESS);
177c0ea7 4512
480b0c5b
GV
4513 fclose (stdin);
4514 fclose (stdout);
4515 fclose (stderr);
4516
4517 if (stdin_save != INVALID_HANDLE_VALUE)
4518 _open_osfhandle ((long) stdin_save, O_TEXT);
4519 else
76b3903d
GV
4520 _open ("nul", O_TEXT | O_NOINHERIT | O_RDONLY);
4521 _fdopen (0, "r");
480b0c5b
GV
4522
4523 if (stdout_save != INVALID_HANDLE_VALUE)
4524 _open_osfhandle ((long) stdout_save, O_TEXT);
4525 else
76b3903d
GV
4526 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
4527 _fdopen (1, "w");
480b0c5b
GV
4528
4529 if (stderr_save != INVALID_HANDLE_VALUE)
4530 _open_osfhandle ((long) stderr_save, O_TEXT);
4531 else
76b3903d
GV
4532 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
4533 _fdopen (2, "w");
480b0c5b
GV
4534 }
4535
4536 /* unfortunately, atexit depends on implementation of malloc */
4537 /* atexit (term_ntproc); */
4538 signal (SIGABRT, term_ntproc);
76b3903d
GV
4539
4540 /* determine which drives are fixed, for GetCachedVolumeInformation */
4541 {
4542 /* GetDriveType must have trailing backslash. */
4543 char drive[] = "A:\\";
4544
4545 /* Loop over all possible drive letters */
4546 while (*drive <= 'Z')
4547 {
4548 /* Record if this drive letter refers to a fixed drive. */
177c0ea7 4549 fixed_drives[DRIVE_INDEX (*drive)] =
76b3903d
GV
4550 (GetDriveType (drive) == DRIVE_FIXED);
4551
4552 (*drive)++;
4553 }
a302c7ae
AI
4554
4555 /* Reset the volume info cache. */
4556 volume_cache = NULL;
76b3903d 4557 }
177c0ea7 4558
d54abccd
GV
4559 /* Check to see if Emacs has been installed correctly. */
4560 check_windows_init_file ();
480b0c5b
GV
4561}
4562
a8c3a596
JR
4563/*
4564 shutdown_handler ensures that buffers' autosave files are
4565 up to date when the user logs off, or the system shuts down.
4566*/
4567BOOL WINAPI shutdown_handler(DWORD type)
4568{
4569 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
4570 if (type == CTRL_CLOSE_EVENT /* User closes console window. */
4571 || type == CTRL_LOGOFF_EVENT /* User logs off. */
4572 || type == CTRL_SHUTDOWN_EVENT) /* User shutsdown. */
4573 {
4574 /* Shut down cleanly, making sure autosave files are up to date. */
4575 shut_down_emacs (0, 0, Qnil);
4576 }
4577
7046f191 4578 /* Allow other handlers to handle this signal. */
a8c3a596
JR
4579 return FALSE;
4580}
4581
9785d95b
BK
4582/*
4583 globals_of_w32 is used to initialize those global variables that
4584 must always be initialized on startup even when the global variable
4585 initialized is non zero (see the function main in emacs.c).
4586*/
9bfb11f9
KS
4587void
4588globals_of_w32 ()
9785d95b 4589{
74258518
JR
4590 HMODULE kernel32 = GetModuleHandle ("kernel32.dll");
4591
4592 get_process_times_fn = (GetProcessTimes_Proc)
4593 GetProcAddress (kernel32, "GetProcessTimes");
4594
9785d95b
BK
4595 g_b_init_is_windows_9x = 0;
4596 g_b_init_open_process_token = 0;
4597 g_b_init_get_token_information = 0;
4598 g_b_init_lookup_account_sid = 0;
4599 g_b_init_get_sid_identifier_authority = 0;
9d95a291
EZ
4600 g_b_init_get_sid_sub_authority = 0;
4601 g_b_init_get_sid_sub_authority_count = 0;
8aaaec6b
EZ
4602 g_b_init_get_file_security = 0;
4603 g_b_init_get_security_descriptor_owner = 0;
4604 g_b_init_get_security_descriptor_group = 0;
4605 g_b_init_is_valid_sid = 0;
a8c3a596
JR
4606 /* The following sets a handler for shutdown notifications for
4607 console apps. This actually applies to Emacs in both console and
4608 GUI modes, since we had to fool windows into thinking emacs is a
4609 console application to get console mode to work. */
4610 SetConsoleCtrlHandler(shutdown_handler, TRUE);
8aaaec6b
EZ
4611
4612 /* "None" is the default group name on standalone workstations. */
4613 strcpy (dflt_group_name, "None");
9785d95b
BK
4614}
4615
aa5ee2a3 4616/* end of w32.c */
ab5796a9
MB
4617
4618/* arch-tag: 90442dd3-37be-482b-b272-ac752e3049f1
4619 (do not change this comment) */