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