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