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