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