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