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