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