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