*** empty log message ***
[bpt/emacs.git] / src / w32.c
CommitLineData
e9e23e23 1/* Utility and Unix shadow routines for GNU Emacs on the Microsoft W32 API.
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
bf794306
EZ
878char *
879emacs_root_dir (void)
880{
881 static char root_dir[FILENAME_MAX];
882 const char *p;
883
884 p = getenv ("emacs_dir");
885 if (p == NULL)
886 abort ();
887 strcpy (root_dir, p);
888 root_dir[parse_root (root_dir, NULL)] = '\0';
889 dostounix_filename (root_dir);
890 return root_dir;
891}
892
480b0c5b
GV
893/* We don't have scripts to automatically determine the system configuration
894 for Emacs before it's compiled, and we don't want to have to make the
895 user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
896 routine. */
897
480b0c5b
GV
898char *
899get_emacs_configuration (void)
900{
901 char *arch, *oem, *os;
c5247da2 902 int build_num;
a302c7ae 903 static char configuration_buffer[32];
480b0c5b
GV
904
905 /* Determine the processor type. */
906 switch (get_processor_type ())
907 {
908
909#ifdef PROCESSOR_INTEL_386
910 case PROCESSOR_INTEL_386:
911 case PROCESSOR_INTEL_486:
912 case PROCESSOR_INTEL_PENTIUM:
913 arch = "i386";
914 break;
915#endif
916
917#ifdef PROCESSOR_INTEL_860
918 case PROCESSOR_INTEL_860:
919 arch = "i860";
920 break;
921#endif
922
923#ifdef PROCESSOR_MIPS_R2000
924 case PROCESSOR_MIPS_R2000:
925 case PROCESSOR_MIPS_R3000:
926 case PROCESSOR_MIPS_R4000:
927 arch = "mips";
928 break;
929#endif
930
931#ifdef PROCESSOR_ALPHA_21064
932 case PROCESSOR_ALPHA_21064:
933 arch = "alpha";
934 break;
935#endif
936
937 default:
938 arch = "unknown";
939 break;
f332b293 940 }
480b0c5b 941
a302c7ae
AI
942 /* Use the OEM field to reflect the compiler/library combination. */
943#ifdef _MSC_VER
944#define COMPILER_NAME "msvc"
945#else
946#ifdef __GNUC__
947#define COMPILER_NAME "mingw"
948#else
949#define COMPILER_NAME "unknown"
950#endif
951#endif
952 oem = COMPILER_NAME;
480b0c5b 953
c5247da2
GV
954 switch (osinfo_cache.dwPlatformId) {
955 case VER_PLATFORM_WIN32_NT:
956 os = "nt";
957 build_num = osinfo_cache.dwBuildNumber;
958 break;
959 case VER_PLATFORM_WIN32_WINDOWS:
960 if (osinfo_cache.dwMinorVersion == 0) {
961 os = "windows95";
962 } else {
963 os = "windows98";
964 }
965 build_num = LOWORD (osinfo_cache.dwBuildNumber);
966 break;
967 case VER_PLATFORM_WIN32s:
968 /* Not supported, should not happen. */
969 os = "windows32s";
970 build_num = LOWORD (osinfo_cache.dwBuildNumber);
971 break;
972 default:
973 os = "unknown";
974 build_num = 0;
975 break;
976 }
977
978 if (osinfo_cache.dwPlatformId == VER_PLATFORM_WIN32_NT) {
979 sprintf (configuration_buffer, "%s-%s-%s%d.%d.%d", arch, oem, os,
980 get_w32_major_version (), get_w32_minor_version (), build_num);
981 } else {
982 sprintf (configuration_buffer, "%s-%s-%s.%d", arch, oem, os, build_num);
983 }
480b0c5b 984
480b0c5b 985 return configuration_buffer;
f332b293
GV
986}
987
a302c7ae
AI
988char *
989get_emacs_configuration_options (void)
990{
991 static char options_buffer[256];
992
993/* Work out the effective configure options for this build. */
994#ifdef _MSC_VER
995#define COMPILER_VERSION "--with-msvc (%d.%02d)", _MSC_VER / 100, _MSC_VER % 100
996#else
997#ifdef __GNUC__
998#define COMPILER_VERSION "--with-gcc (%d.%d)", __GNUC__, __GNUC_MINOR__
999#else
1000#define COMPILER_VERSION ""
1001#endif
1002#endif
1003
1004 sprintf (options_buffer, COMPILER_VERSION);
1005#ifdef EMACSDEBUG
1006 strcat (options_buffer, " --no-opt");
1007#endif
1008#ifdef USER_CFLAGS
1009 strcat (options_buffer, " --cflags");
1010 strcat (options_buffer, USER_CFLAGS);
1011#endif
1012#ifdef USER_LDFLAGS
1013 strcat (options_buffer, " --ldflags");
1014 strcat (options_buffer, USER_LDFLAGS);
1015#endif
1016 return options_buffer;
1017}
1018
1019
35f0d482
KH
1020#include <sys/timeb.h>
1021
1022/* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
1023void
1024gettimeofday (struct timeval *tv, struct timezone *tz)
1025{
a302c7ae 1026 struct timeb tb;
35f0d482
KH
1027 _ftime (&tb);
1028
1029 tv->tv_sec = tb.time;
1030 tv->tv_usec = tb.millitm * 1000L;
1031 if (tz)
1032 {
1033 tz->tz_minuteswest = tb.timezone; /* minutes west of Greenwich */
1034 tz->tz_dsttime = tb.dstflag; /* type of dst correction */
1035 }
1036}
35f0d482 1037
480b0c5b 1038/* ------------------------------------------------------------------------- */
fbd6baed 1039/* IO support and wrapper functions for W32 API. */
480b0c5b 1040/* ------------------------------------------------------------------------- */
95ed0025 1041
480b0c5b
GV
1042/* Place a wrapper around the MSVC version of ctime. It returns NULL
1043 on network directories, so we handle that case here.
1044 (Ulrich Leodolter, 1/11/95). */
1045char *
1046sys_ctime (const time_t *t)
1047{
1048 char *str = (char *) ctime (t);
1049 return (str ? str : "Sun Jan 01 00:00:00 1970");
1050}
1051
1052/* Emulate sleep...we could have done this with a define, but that
1053 would necessitate including windows.h in the files that used it.
1054 This is much easier. */
1055void
1056sys_sleep (int seconds)
1057{
1058 Sleep (seconds * 1000);
1059}
1060
76b3903d 1061/* Internal MSVC functions for low-level descriptor munging */
480b0c5b
GV
1062extern int __cdecl _set_osfhnd (int fd, long h);
1063extern int __cdecl _free_osfhnd (int fd);
1064
1065/* parallel array of private info on file handles */
1066filedesc fd_info [ MAXDESC ];
1067
76b3903d
GV
1068typedef struct volume_info_data {
1069 struct volume_info_data * next;
1070
1071 /* time when info was obtained */
1072 DWORD timestamp;
1073
1074 /* actual volume info */
1075 char * root_dir;
480b0c5b
GV
1076 DWORD serialnum;
1077 DWORD maxcomp;
1078 DWORD flags;
76b3903d
GV
1079 char * name;
1080 char * type;
1081} volume_info_data;
1082
1083/* Global referenced by various functions. */
1084static volume_info_data volume_info;
1085
1086/* Vector to indicate which drives are local and fixed (for which cached
1087 data never expires). */
1088static BOOL fixed_drives[26];
1089
1090/* Consider cached volume information to be stale if older than 10s,
1091 at least for non-local drives. Info for fixed drives is never stale. */
1092#define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
1093#define VOLINFO_STILL_VALID( root_dir, info ) \
1094 ( ( isalpha (root_dir[0]) && \
1095 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
1096 || GetTickCount () - info->timestamp < 10000 )
1097
1098/* Cache support functions. */
1099
1100/* Simple linked list with linear search is sufficient. */
1101static volume_info_data *volume_cache = NULL;
1102
1103static volume_info_data *
1104lookup_volume_info (char * root_dir)
1105{
1106 volume_info_data * info;
1107
1108 for (info = volume_cache; info; info = info->next)
1109 if (stricmp (info->root_dir, root_dir) == 0)
1110 break;
1111 return info;
1112}
1113
1114static void
1115add_volume_info (char * root_dir, volume_info_data * info)
1116{
a302c7ae 1117 info->root_dir = xstrdup (root_dir);
76b3903d
GV
1118 info->next = volume_cache;
1119 volume_cache = info;
1120}
1121
1122
1123/* Wrapper for GetVolumeInformation, which uses caching to avoid
1124 performance penalty (~2ms on 486 for local drives, 7.5ms for local
1125 cdrom drive, ~5-10ms or more for remote drives on LAN). */
1126volume_info_data *
1127GetCachedVolumeInformation (char * root_dir)
1128{
1129 volume_info_data * info;
1130 char default_root[ MAX_PATH ];
1131
1132 /* NULL for root_dir means use root from current directory. */
1133 if (root_dir == NULL)
1134 {
1135 if (GetCurrentDirectory (MAX_PATH, default_root) == 0)
1136 return NULL;
1137 parse_root (default_root, &root_dir);
1138 *root_dir = 0;
1139 root_dir = default_root;
1140 }
1141
1142 /* Local fixed drives can be cached permanently. Removable drives
1143 cannot be cached permanently, since the volume name and serial
1144 number (if nothing else) can change. Remote drives should be
1145 treated as if they are removable, since there is no sure way to
1146 tell whether they are or not. Also, the UNC association of drive
1147 letters mapped to remote volumes can be changed at any time (even
1148 by other processes) without notice.
1149
1150 As a compromise, so we can benefit from caching info for remote
1151 volumes, we use a simple expiry mechanism to invalidate cache
1152 entries that are more than ten seconds old. */
1153
1154#if 0
1155 /* No point doing this, because WNetGetConnection is even slower than
1156 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
1157 GetDriveType is about the only call of this type which does not
1158 involve network access, and so is extremely quick). */
1159
1160 /* Map drive letter to UNC if remote. */
1161 if ( isalpha( root_dir[0] ) && !fixed[ DRIVE_INDEX( root_dir[0] ) ] )
1162 {
1163 char remote_name[ 256 ];
1164 char drive[3] = { root_dir[0], ':' };
1165
1166 if (WNetGetConnection (drive, remote_name, sizeof (remote_name))
1167 == NO_ERROR)
1168 /* do something */ ;
1169 }
1170#endif
1171
1172 info = lookup_volume_info (root_dir);
1173
1174 if (info == NULL || ! VOLINFO_STILL_VALID (root_dir, info))
1175 {
1176 char name[ 256 ];
1177 DWORD serialnum;
1178 DWORD maxcomp;
1179 DWORD flags;
1180 char type[ 256 ];
1181
1182 /* Info is not cached, or is stale. */
1183 if (!GetVolumeInformation (root_dir,
1184 name, sizeof (name),
1185 &serialnum,
1186 &maxcomp,
1187 &flags,
1188 type, sizeof (type)))
1189 return NULL;
1190
1191 /* Cache the volume information for future use, overwriting existing
1192 entry if present. */
1193 if (info == NULL)
1194 {
1195 info = (volume_info_data *) xmalloc (sizeof (volume_info_data));
1196 add_volume_info (root_dir, info);
1197 }
1198 else
1199 {
a302c7ae
AI
1200 xfree (info->name);
1201 xfree (info->type);
76b3903d
GV
1202 }
1203
a302c7ae 1204 info->name = xstrdup (name);
76b3903d
GV
1205 info->serialnum = serialnum;
1206 info->maxcomp = maxcomp;
1207 info->flags = flags;
a302c7ae 1208 info->type = xstrdup (type);
76b3903d
GV
1209 info->timestamp = GetTickCount ();
1210 }
1211
1212 return info;
1213}
480b0c5b
GV
1214
1215/* Get information on the volume where name is held; set path pointer to
1216 start of pathname in name (past UNC header\volume header if present). */
1217int
1218get_volume_info (const char * name, const char ** pPath)
95ed0025 1219{
480b0c5b
GV
1220 char temp[MAX_PATH];
1221 char *rootname = NULL; /* default to current volume */
76b3903d 1222 volume_info_data * info;
480b0c5b
GV
1223
1224 if (name == NULL)
1225 return FALSE;
1226
1227 /* find the root name of the volume if given */
1228 if (isalpha (name[0]) && name[1] == ':')
1229 {
1230 rootname = temp;
1231 temp[0] = *name++;
1232 temp[1] = *name++;
1233 temp[2] = '\\';
1234 temp[3] = 0;
1235 }
1236 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
95ed0025 1237 {
480b0c5b
GV
1238 char *str = temp;
1239 int slashes = 4;
1240 rootname = temp;
1241 do
1242 {
1243 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
1244 break;
1245 *str++ = *name++;
1246 }
1247 while ( *name );
1248
480b0c5b
GV
1249 *str++ = '\\';
1250 *str = 0;
95ed0025 1251 }
480b0c5b
GV
1252
1253 if (pPath)
1254 *pPath = name;
1255
76b3903d
GV
1256 info = GetCachedVolumeInformation (rootname);
1257 if (info != NULL)
95ed0025 1258 {
76b3903d
GV
1259 /* Set global referenced by other functions. */
1260 volume_info = *info;
480b0c5b 1261 return TRUE;
95ed0025 1262 }
480b0c5b
GV
1263 return FALSE;
1264}
1265
1266/* Determine if volume is FAT format (ie. only supports short 8.3
1267 names); also set path pointer to start of pathname in name. */
1268int
1269is_fat_volume (const char * name, const char ** pPath)
1270{
1271 if (get_volume_info (name, pPath))
1272 return (volume_info.maxcomp == 12);
1273 return FALSE;
1274}
1275
1276/* Map filename to a legal 8.3 name if necessary. */
1277const char *
fbd6baed 1278map_w32_filename (const char * name, const char ** pPath)
480b0c5b
GV
1279{
1280 static char shortname[MAX_PATH];
1281 char * str = shortname;
1282 char c;
480b0c5b 1283 char * path;
76b3903d 1284 const char * save_name = name;
480b0c5b 1285
ca149beb
AI
1286 if (strlen (name) >= MAX_PATH)
1287 {
1288 /* Return a filename which will cause callers to fail. */
1289 strcpy (shortname, "?");
1290 return shortname;
1291 }
1292
a302c7ae 1293 if (is_fat_volume (name, (const char **)&path)) /* truncate to 8.3 */
95ed0025 1294 {
480b0c5b
GV
1295 register int left = 8; /* maximum number of chars in part */
1296 register int extn = 0; /* extension added? */
1297 register int dots = 2; /* maximum number of dots allowed */
1298
1299 while (name < path)
1300 *str++ = *name++; /* skip past UNC header */
1301
1302 while ((c = *name++))
1303 {
1304 switch ( c )
1305 {
1306 case '\\':
1307 case '/':
1308 *str++ = '\\';
1309 extn = 0; /* reset extension flags */
1310 dots = 2; /* max 2 dots */
1311 left = 8; /* max length 8 for main part */
1312 break;
1313 case ':':
1314 *str++ = ':';
1315 extn = 0; /* reset extension flags */
1316 dots = 2; /* max 2 dots */
1317 left = 8; /* max length 8 for main part */
1318 break;
1319 case '.':
1320 if ( dots )
1321 {
1322 /* Convert path components of the form .xxx to _xxx,
1323 but leave . and .. as they are. This allows .emacs
1324 to be read as _emacs, for example. */
1325
1326 if (! *name ||
1327 *name == '.' ||
1328 IS_DIRECTORY_SEP (*name))
1329 {
1330 *str++ = '.';
1331 dots--;
1332 }
1333 else
1334 {
1335 *str++ = '_';
1336 left--;
1337 dots = 0;
1338 }
1339 }
1340 else if ( !extn )
1341 {
1342 *str++ = '.';
1343 extn = 1; /* we've got an extension */
1344 left = 3; /* 3 chars in extension */
1345 }
1346 else
1347 {
1348 /* any embedded dots after the first are converted to _ */
1349 *str++ = '_';
1350 }
1351 break;
1352 case '~':
1353 case '#': /* don't lose these, they're important */
1354 if ( ! left )
1355 str[-1] = c; /* replace last character of part */
1356 /* FALLTHRU */
1357 default:
1358 if ( left )
1359 {
1360 *str++ = tolower (c); /* map to lower case (looks nicer) */
1361 left--;
1362 dots = 0; /* started a path component */
1363 }
1364 break;
1365 }
1366 }
1367 *str = '\0';
fc85cb29
RS
1368 }
1369 else
1370 {
1371 strcpy (shortname, name);
1372 unixtodos_filename (shortname);
95ed0025 1373 }
480b0c5b
GV
1374
1375 if (pPath)
76b3903d 1376 *pPath = shortname + (path - save_name);
480b0c5b 1377
fc85cb29 1378 return shortname;
480b0c5b
GV
1379}
1380
b3308d2e
KH
1381static int
1382is_exec (const char * name)
1383{
1384 char * p = strrchr (name, '.');
1385 return
1386 (p != NULL
1387 && (stricmp (p, ".exe") == 0 ||
1388 stricmp (p, ".com") == 0 ||
1389 stricmp (p, ".bat") == 0 ||
1390 stricmp (p, ".cmd") == 0));
1391}
1392
76b3903d
GV
1393/* Emulate the Unix directory procedures opendir, closedir,
1394 and readdir. We can't use the procedures supplied in sysdep.c,
1395 so we provide them here. */
1396
1397struct direct dir_static; /* simulated directory contents */
1398static HANDLE dir_find_handle = INVALID_HANDLE_VALUE;
1399static int dir_is_fat;
1400static char dir_pathname[MAXPATHLEN+1];
1401static WIN32_FIND_DATA dir_find_data;
1402
9d3355d1
GV
1403/* Support shares on a network resource as subdirectories of a read-only
1404 root directory. */
1405static HANDLE wnet_enum_handle = INVALID_HANDLE_VALUE;
1406HANDLE open_unc_volume (char *);
1407char *read_unc_volume (HANDLE, char *, int);
1408void close_unc_volume (HANDLE);
1409
76b3903d
GV
1410DIR *
1411opendir (char *filename)
1412{
1413 DIR *dirp;
1414
1415 /* Opening is done by FindFirstFile. However, a read is inherent to
1416 this operation, so we defer the open until read time. */
1417
76b3903d
GV
1418 if (dir_find_handle != INVALID_HANDLE_VALUE)
1419 return NULL;
9d3355d1
GV
1420 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
1421 return NULL;
1422
1423 if (is_unc_volume (filename))
1424 {
1425 wnet_enum_handle = open_unc_volume (filename);
1426 if (wnet_enum_handle == INVALID_HANDLE_VALUE)
1427 return NULL;
1428 }
1429
1430 if (!(dirp = (DIR *) malloc (sizeof (DIR))))
1431 return NULL;
76b3903d
GV
1432
1433 dirp->dd_fd = 0;
1434 dirp->dd_loc = 0;
1435 dirp->dd_size = 0;
1436
1437 strncpy (dir_pathname, map_w32_filename (filename, NULL), MAXPATHLEN);
1438 dir_pathname[MAXPATHLEN] = '\0';
1439 dir_is_fat = is_fat_volume (filename, NULL);
1440
1441 return dirp;
1442}
1443
1444void
1445closedir (DIR *dirp)
1446{
1447 /* If we have a find-handle open, close it. */
1448 if (dir_find_handle != INVALID_HANDLE_VALUE)
1449 {
1450 FindClose (dir_find_handle);
1451 dir_find_handle = INVALID_HANDLE_VALUE;
1452 }
9d3355d1
GV
1453 else if (wnet_enum_handle != INVALID_HANDLE_VALUE)
1454 {
1455 close_unc_volume (wnet_enum_handle);
1456 wnet_enum_handle = INVALID_HANDLE_VALUE;
1457 }
76b3903d
GV
1458 xfree ((char *) dirp);
1459}
1460
1461struct direct *
1462readdir (DIR *dirp)
1463{
9d3355d1
GV
1464 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
1465 {
1466 if (!read_unc_volume (wnet_enum_handle,
1467 dir_find_data.cFileName,
1468 MAX_PATH))
1469 return NULL;
1470 }
76b3903d 1471 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
9d3355d1 1472 else if (dir_find_handle == INVALID_HANDLE_VALUE)
76b3903d
GV
1473 {
1474 char filename[MAXNAMLEN + 3];
1475 int ln;
1476
1477 strcpy (filename, dir_pathname);
1478 ln = strlen (filename) - 1;
1479 if (!IS_DIRECTORY_SEP (filename[ln]))
1480 strcat (filename, "\\");
1481 strcat (filename, "*");
1482
1483 dir_find_handle = FindFirstFile (filename, &dir_find_data);
1484
1485 if (dir_find_handle == INVALID_HANDLE_VALUE)
1486 return NULL;
1487 }
1488 else
1489 {
1490 if (!FindNextFile (dir_find_handle, &dir_find_data))
1491 return NULL;
1492 }
1493
1494 /* Emacs never uses this value, so don't bother making it match
1495 value returned by stat(). */
1496 dir_static.d_ino = 1;
1497
1498 dir_static.d_reclen = sizeof (struct direct) - MAXNAMLEN + 3 +
1499 dir_static.d_namlen - dir_static.d_namlen % 4;
1500
1501 dir_static.d_namlen = strlen (dir_find_data.cFileName);
1502 strcpy (dir_static.d_name, dir_find_data.cFileName);
1503 if (dir_is_fat)
1504 _strlwr (dir_static.d_name);
1505 else if (!NILP (Vw32_downcase_file_names))
1506 {
1507 register char *p;
1508 for (p = dir_static.d_name; *p; p++)
1509 if (*p >= 'a' && *p <= 'z')
1510 break;
1511 if (!*p)
1512 _strlwr (dir_static.d_name);
1513 }
1514
1515 return &dir_static;
1516}
1517
9d3355d1
GV
1518HANDLE
1519open_unc_volume (char *path)
1520{
1521 NETRESOURCE nr;
1522 HANDLE henum;
1523 int result;
1524
1525 nr.dwScope = RESOURCE_GLOBALNET;
1526 nr.dwType = RESOURCETYPE_DISK;
1527 nr.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
1528 nr.dwUsage = RESOURCEUSAGE_CONTAINER;
1529 nr.lpLocalName = NULL;
1530 nr.lpRemoteName = map_w32_filename (path, NULL);
1531 nr.lpComment = NULL;
1532 nr.lpProvider = NULL;
1533
1534 result = WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
1535 RESOURCEUSAGE_CONNECTABLE, &nr, &henum);
1536
1537 if (result == NO_ERROR)
1538 return henum;
1539 else
1540 return INVALID_HANDLE_VALUE;
1541}
1542
1543char *
1544read_unc_volume (HANDLE henum, char *readbuf, int size)
1545{
a302c7ae 1546 DWORD count;
9d3355d1 1547 int result;
a302c7ae 1548 DWORD bufsize = 512;
9d3355d1
GV
1549 char *buffer;
1550 char *ptr;
1551
1552 count = 1;
1553 buffer = alloca (bufsize);
1554 result = WNetEnumResource (wnet_enum_handle, &count, buffer, &bufsize);
1555 if (result != NO_ERROR)
1556 return NULL;
1557
1558 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
1559 ptr = ((LPNETRESOURCE) buffer)->lpRemoteName;
1560 ptr += 2;
1561 while (*ptr && !IS_DIRECTORY_SEP (*ptr)) ptr++;
1562 ptr++;
1563
1564 strncpy (readbuf, ptr, size);
1565 return readbuf;
1566}
1567
1568void
1569close_unc_volume (HANDLE henum)
1570{
1571 if (henum != INVALID_HANDLE_VALUE)
1572 WNetCloseEnum (henum);
1573}
1574
1575DWORD
1576unc_volume_file_attributes (char *path)
1577{
1578 HANDLE henum;
1579 DWORD attrs;
1580
1581 henum = open_unc_volume (path);
1582 if (henum == INVALID_HANDLE_VALUE)
1583 return -1;
1584
1585 attrs = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY;
1586
1587 close_unc_volume (henum);
1588
1589 return attrs;
1590}
1591
480b0c5b
GV
1592
1593/* Shadow some MSVC runtime functions to map requests for long filenames
1594 to reasonable short names if necessary. This was originally added to
1595 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
1596 long file names. */
1597
1598int
1599sys_access (const char * path, int mode)
1600{
b3308d2e
KH
1601 DWORD attributes;
1602
1603 /* MSVC implementation doesn't recognize D_OK. */
1604 path = map_w32_filename (path, NULL);
9d3355d1
GV
1605 if (is_unc_volume (path))
1606 {
1607 attributes = unc_volume_file_attributes (path);
1608 if (attributes == -1) {
1609 errno = EACCES;
1610 return -1;
1611 }
1612 }
1613 else if ((attributes = GetFileAttributes (path)) == -1)
b3308d2e
KH
1614 {
1615 /* Should try mapping GetLastError to errno; for now just indicate
1616 that path doesn't exist. */
1617 errno = EACCES;
1618 return -1;
1619 }
1620 if ((mode & X_OK) != 0 && !is_exec (path))
1621 {
1622 errno = EACCES;
1623 return -1;
1624 }
1625 if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0)
1626 {
1627 errno = EACCES;
1628 return -1;
1629 }
1630 if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
1631 {
1632 errno = EACCES;
1633 return -1;
1634 }
1635 return 0;
480b0c5b
GV
1636}
1637
1638int
1639sys_chdir (const char * path)
1640{
fbd6baed 1641 return _chdir (map_w32_filename (path, NULL));
480b0c5b
GV
1642}
1643
1644int
1645sys_chmod (const char * path, int mode)
1646{
fbd6baed 1647 return _chmod (map_w32_filename (path, NULL), mode);
480b0c5b
GV
1648}
1649
1650int
1651sys_creat (const char * path, int mode)
1652{
fbd6baed 1653 return _creat (map_w32_filename (path, NULL), mode);
480b0c5b
GV
1654}
1655
1656FILE *
1657sys_fopen(const char * path, const char * mode)
1658{
1659 int fd;
1660 int oflag;
1661 const char * mode_save = mode;
1662
1663 /* Force all file handles to be non-inheritable. This is necessary to
1664 ensure child processes don't unwittingly inherit handles that might
1665 prevent future file access. */
1666
1667 if (mode[0] == 'r')
1668 oflag = O_RDONLY;
1669 else if (mode[0] == 'w' || mode[0] == 'a')
1670 oflag = O_WRONLY | O_CREAT | O_TRUNC;
95ed0025 1671 else
480b0c5b
GV
1672 return NULL;
1673
1674 /* Only do simplistic option parsing. */
1675 while (*++mode)
1676 if (mode[0] == '+')
1677 {
1678 oflag &= ~(O_RDONLY | O_WRONLY);
1679 oflag |= O_RDWR;
1680 }
1681 else if (mode[0] == 'b')
1682 {
1683 oflag &= ~O_TEXT;
1684 oflag |= O_BINARY;
1685 }
1686 else if (mode[0] == 't')
1687 {
1688 oflag &= ~O_BINARY;
1689 oflag |= O_TEXT;
1690 }
1691 else break;
1692
fbd6baed 1693 fd = _open (map_w32_filename (path, NULL), oflag | _O_NOINHERIT, 0644);
480b0c5b
GV
1694 if (fd < 0)
1695 return NULL;
1696
76b3903d 1697 return _fdopen (fd, mode_save);
95ed0025 1698}
480b0c5b 1699
76b3903d 1700/* This only works on NTFS volumes, but is useful to have. */
480b0c5b 1701int
76b3903d 1702sys_link (const char * old, const char * new)
480b0c5b 1703{
76b3903d
GV
1704 HANDLE fileh;
1705 int result = -1;
1706 char oldname[MAX_PATH], newname[MAX_PATH];
1707
1708 if (old == NULL || new == NULL)
1709 {
1710 errno = ENOENT;
1711 return -1;
1712 }
1713
1714 strcpy (oldname, map_w32_filename (old, NULL));
1715 strcpy (newname, map_w32_filename (new, NULL));
1716
1717 fileh = CreateFile (oldname, 0, 0, NULL, OPEN_EXISTING,
1718 FILE_FLAG_BACKUP_SEMANTICS, NULL);
1719 if (fileh != INVALID_HANDLE_VALUE)
1720 {
1721 int wlen;
1722
1723 /* Confusingly, the "alternate" stream name field does not apply
1724 when restoring a hard link, and instead contains the actual
1725 stream data for the link (ie. the name of the link to create).
1726 The WIN32_STREAM_ID structure before the cStreamName field is
1727 the stream header, which is then immediately followed by the
1728 stream data. */
1729
1730 struct {
1731 WIN32_STREAM_ID wid;
1732 WCHAR wbuffer[MAX_PATH]; /* extra space for link name */
1733 } data;
1734
1735 wlen = MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, newname, -1,
1736 data.wid.cStreamName, MAX_PATH);
1737 if (wlen > 0)
1738 {
1739 LPVOID context = NULL;
1740 DWORD wbytes = 0;
1741
1742 data.wid.dwStreamId = BACKUP_LINK;
1743 data.wid.dwStreamAttributes = 0;
1744 data.wid.Size.LowPart = wlen * sizeof(WCHAR);
1745 data.wid.Size.HighPart = 0;
1746 data.wid.dwStreamNameSize = 0;
1747
1748 if (BackupWrite (fileh, (LPBYTE)&data,
1749 offsetof (WIN32_STREAM_ID, cStreamName)
1750 + data.wid.Size.LowPart,
1751 &wbytes, FALSE, FALSE, &context)
1752 && BackupWrite (fileh, NULL, 0, &wbytes, TRUE, FALSE, &context))
1753 {
1754 /* succeeded */
1755 result = 0;
1756 }
1757 else
1758 {
1759 /* Should try mapping GetLastError to errno; for now just
1760 indicate a general error (eg. links not supported). */
1761 errno = EINVAL; // perhaps EMLINK?
1762 }
1763 }
1764
1765 CloseHandle (fileh);
1766 }
1767 else
1768 errno = ENOENT;
1769
1770 return result;
480b0c5b
GV
1771}
1772
1773int
1774sys_mkdir (const char * path)
1775{
fbd6baed 1776 return _mkdir (map_w32_filename (path, NULL));
480b0c5b
GV
1777}
1778
9d1778b1
RS
1779/* Because of long name mapping issues, we need to implement this
1780 ourselves. Also, MSVC's _mktemp returns NULL when it can't generate
1781 a unique name, instead of setting the input template to an empty
1782 string.
1783
1784 Standard algorithm seems to be use pid or tid with a letter on the
1785 front (in place of the 6 X's) and cycle through the letters to find a
1786 unique name. We extend that to allow any reasonable character as the
1787 first of the 6 X's. */
480b0c5b
GV
1788char *
1789sys_mktemp (char * template)
1790{
9d1778b1
RS
1791 char * p;
1792 int i;
1793 unsigned uid = GetCurrentThreadId ();
1794 static char first_char[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
1795
1796 if (template == NULL)
1797 return NULL;
1798 p = template + strlen (template);
1799 i = 5;
1800 /* replace up to the last 5 X's with uid in decimal */
1801 while (--p >= template && p[0] == 'X' && --i >= 0)
1802 {
1803 p[0] = '0' + uid % 10;
1804 uid /= 10;
1805 }
1806
1807 if (i < 0 && p[0] == 'X')
1808 {
1809 i = 0;
1810 do
1811 {
1812 int save_errno = errno;
1813 p[0] = first_char[i];
1814 if (sys_access (template, 0) < 0)
1815 {
1816 errno = save_errno;
1817 return template;
1818 }
1819 }
1820 while (++i < sizeof (first_char));
1821 }
1822
1823 /* Template is badly formed or else we can't generate a unique name,
1824 so return empty string */
1825 template[0] = 0;
1826 return template;
480b0c5b
GV
1827}
1828
1829int
1830sys_open (const char * path, int oflag, int mode)
1831{
302f0b29
GM
1832 const char* mpath = map_w32_filename (path, NULL);
1833 /* Try to open file without _O_CREAT, to be able to write to hidden
1834 and system files. Force all file handles to be
1835 non-inheritable. */
1836 int res = _open (mpath, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
1837 if (res >= 0)
1838 return res;
1839 return _open (mpath, oflag | _O_NOINHERIT, mode);
480b0c5b
GV
1840}
1841
1842int
1843sys_rename (const char * oldname, const char * newname)
1844{
cfb5e855 1845 BOOL result;
b3308d2e 1846 char temp[MAX_PATH];
480b0c5b 1847
e9e23e23 1848 /* MoveFile on Windows 95 doesn't correctly change the short file name
5162ffce
MB
1849 alias in a number of circumstances (it is not easy to predict when
1850 just by looking at oldname and newname, unfortunately). In these
1851 cases, renaming through a temporary name avoids the problem.
1852
e9e23e23 1853 A second problem on Windows 95 is that renaming through a temp name when
5162ffce
MB
1854 newname is uppercase fails (the final long name ends up in
1855 lowercase, although the short alias might be uppercase) UNLESS the
1856 long temp name is not 8.3.
1857
e9e23e23 1858 So, on Windows 95 we always rename through a temp name, and we make sure
5162ffce 1859 the temp name has a long extension to ensure correct renaming. */
480b0c5b 1860
fbd6baed 1861 strcpy (temp, map_w32_filename (oldname, NULL));
480b0c5b 1862
76b3903d 1863 if (os_subtype == OS_WIN95)
480b0c5b 1864 {
b3308d2e 1865 char * o;
480b0c5b 1866 char * p;
b3308d2e
KH
1867 int i = 0;
1868
1869 oldname = map_w32_filename (oldname, NULL);
1870 if (o = strrchr (oldname, '\\'))
1871 o++;
1872 else
1873 o = (char *) oldname;
480b0c5b 1874
480b0c5b
GV
1875 if (p = strrchr (temp, '\\'))
1876 p++;
1877 else
1878 p = temp;
b3308d2e
KH
1879
1880 do
1881 {
1882 /* Force temp name to require a manufactured 8.3 alias - this
1883 seems to make the second rename work properly. */
f313ee82 1884 sprintf (p, "_.%s.%u", o, i);
b3308d2e 1885 i++;
58f0cb7e 1886 result = rename (oldname, temp);
b3308d2e
KH
1887 }
1888 /* This loop must surely terminate! */
cfb5e855 1889 while (result < 0 && errno == EEXIST);
58f0cb7e 1890 if (result < 0)
480b0c5b
GV
1891 return -1;
1892 }
1893
1894 /* Emulate Unix behaviour - newname is deleted if it already exists
5162ffce 1895 (at least if it is a file; don't do this for directories).
76b3903d 1896
b3308d2e
KH
1897 Since we mustn't do this if we are just changing the case of the
1898 file name (we would end up deleting the file we are trying to
1899 rename!), we let rename detect if the destination file already
1900 exists - that way we avoid the possible pitfalls of trying to
1901 determine ourselves whether two names really refer to the same
1902 file, which is not always possible in the general case. (Consider
1903 all the permutations of shared or subst'd drives, etc.) */
1904
1905 newname = map_w32_filename (newname, NULL);
eb9ea53f 1906 result = rename (temp, newname);
b3308d2e
KH
1907
1908 if (result < 0
cfb5e855 1909 && errno == EEXIST
b3308d2e
KH
1910 && _chmod (newname, 0666) == 0
1911 && _unlink (newname) == 0)
1912 result = rename (temp, newname);
480b0c5b 1913
eb9ea53f 1914 return result;
480b0c5b
GV
1915}
1916
1917int
1918sys_rmdir (const char * path)
1919{
fbd6baed 1920 return _rmdir (map_w32_filename (path, NULL));
480b0c5b
GV
1921}
1922
1923int
1924sys_unlink (const char * path)
1925{
16bb7578
GV
1926 path = map_w32_filename (path, NULL);
1927
1928 /* On Unix, unlink works without write permission. */
1929 _chmod (path, 0666);
1930 return _unlink (path);
480b0c5b
GV
1931}
1932
1933static FILETIME utc_base_ft;
1934static long double utc_base;
1935static int init = 0;
1936
1937static time_t
1938convert_time (FILETIME ft)
1939{
1940 long double ret;
1941
1942 if (!init)
1943 {
1944 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
1945 SYSTEMTIME st;
1946
1947 st.wYear = 1970;
1948 st.wMonth = 1;
1949 st.wDay = 1;
1950 st.wHour = 0;
1951 st.wMinute = 0;
1952 st.wSecond = 0;
1953 st.wMilliseconds = 0;
1954
1955 SystemTimeToFileTime (&st, &utc_base_ft);
1956 utc_base = (long double) utc_base_ft.dwHighDateTime
1957 * 4096 * 1024 * 1024 + utc_base_ft.dwLowDateTime;
1958 init = 1;
1959 }
1960
1961 if (CompareFileTime (&ft, &utc_base_ft) < 0)
1962 return 0;
1963
1964 ret = (long double) ft.dwHighDateTime * 4096 * 1024 * 1024 + ft.dwLowDateTime;
1965 ret -= utc_base;
1966 return (time_t) (ret * 1e-7);
1967}
1968
480b0c5b
GV
1969void
1970convert_from_time_t (time_t time, FILETIME * pft)
1971{
1972 long double tmp;
1973
1974 if (!init)
1975 {
1976 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
1977 SYSTEMTIME st;
1978
1979 st.wYear = 1970;
1980 st.wMonth = 1;
1981 st.wDay = 1;
1982 st.wHour = 0;
1983 st.wMinute = 0;
1984 st.wSecond = 0;
1985 st.wMilliseconds = 0;
1986
1987 SystemTimeToFileTime (&st, &utc_base_ft);
1988 utc_base = (long double) utc_base_ft.dwHighDateTime
1989 * 4096 * 1024 * 1024 + utc_base_ft.dwLowDateTime;
1990 init = 1;
1991 }
1992
1993 /* time in 100ns units since 1-Jan-1601 */
1994 tmp = (long double) time * 1e7 + utc_base;
1995 pft->dwHighDateTime = (DWORD) (tmp / (4096.0 * 1024 * 1024));
16bb7578 1996 pft->dwLowDateTime = (DWORD) (tmp - (4096.0 * 1024 * 1024) * pft->dwHighDateTime);
480b0c5b 1997}
480b0c5b 1998
76b3903d
GV
1999#if 0
2000/* No reason to keep this; faking inode values either by hashing or even
2001 using the file index from GetInformationByHandle, is not perfect and
2002 so by default Emacs doesn't use the inode values on Windows.
2003 Instead, we now determine file-truename correctly (except for
2004 possible drive aliasing etc). */
2005
2006/* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
480b0c5b 2007static unsigned
76b3903d 2008hashval (const unsigned char * str)
480b0c5b
GV
2009{
2010 unsigned h = 0;
480b0c5b
GV
2011 while (*str)
2012 {
2013 h = (h << 4) + *str++;
76b3903d 2014 h ^= (h >> 28);
480b0c5b
GV
2015 }
2016 return h;
2017}
2018
2019/* Return the hash value of the canonical pathname, excluding the
2020 drive/UNC header, to get a hopefully unique inode number. */
76b3903d 2021static DWORD
480b0c5b
GV
2022generate_inode_val (const char * name)
2023{
2024 char fullname[ MAX_PATH ];
2025 char * p;
2026 unsigned hash;
2027
76b3903d
GV
2028 /* Get the truly canonical filename, if it exists. (Note: this
2029 doesn't resolve aliasing due to subst commands, or recognise hard
2030 links. */
2031 if (!w32_get_long_filename ((char *)name, fullname, MAX_PATH))
2032 abort ();
2033
2034 parse_root (fullname, &p);
fbd6baed 2035 /* Normal W32 filesystems are still case insensitive. */
480b0c5b 2036 _strlwr (p);
76b3903d 2037 return hashval (p);
480b0c5b
GV
2038}
2039
76b3903d
GV
2040#endif
2041
480b0c5b
GV
2042/* MSVC stat function can't cope with UNC names and has other bugs, so
2043 replace it with our own. This also allows us to calculate consistent
2044 inode values without hacks in the main Emacs code. */
2045int
2046stat (const char * path, struct stat * buf)
2047{
eb9ea53f 2048 char *name, *r;
480b0c5b
GV
2049 WIN32_FIND_DATA wfd;
2050 HANDLE fh;
76b3903d 2051 DWORD fake_inode;
480b0c5b
GV
2052 int permission;
2053 int len;
2054 int rootdir = FALSE;
2055
2056 if (path == NULL || buf == NULL)
2057 {
2058 errno = EFAULT;
2059 return -1;
2060 }
2061
fbd6baed 2062 name = (char *) map_w32_filename (path, &path);
9ab8560d 2063 /* must be valid filename, no wild cards or other invalid characters */
bb1584c8 2064 if (strpbrk (name, "*?|<>\""))
480b0c5b
GV
2065 {
2066 errno = ENOENT;
2067 return -1;
2068 }
2069
eb9ea53f
GV
2070 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
2071 r = IS_DEVICE_SEP (name[1]) ? &name[2] : name;
2072 if (IS_DIRECTORY_SEP (r[0]) && r[1] == '.' && r[2] == '.' && r[3] == '\0')
2073 {
2074 r[1] = r[2] = '\0';
2075 }
2076
480b0c5b
GV
2077 /* Remove trailing directory separator, unless name is the root
2078 directory of a drive or UNC volume in which case ensure there
2079 is a trailing separator. */
2080 len = strlen (name);
2081 rootdir = (path >= name + len - 1
2082 && (IS_DIRECTORY_SEP (*path) || *path == 0));
2083 name = strcpy (alloca (len + 2), name);
2084
9d3355d1
GV
2085 if (is_unc_volume (name))
2086 {
2087 DWORD attrs = unc_volume_file_attributes (name);
2088
2089 if (attrs == -1)
2090 return -1;
2091
2092 memset (&wfd, 0, sizeof (wfd));
2093 wfd.dwFileAttributes = attrs;
2094 wfd.ftCreationTime = utc_base_ft;
2095 wfd.ftLastAccessTime = utc_base_ft;
2096 wfd.ftLastWriteTime = utc_base_ft;
2097 strcpy (wfd.cFileName, name);
2098 }
2099 else if (rootdir)
480b0c5b
GV
2100 {
2101 if (!IS_DIRECTORY_SEP (name[len-1]))
2102 strcat (name, "\\");
2103 if (GetDriveType (name) < 2)
2104 {
2105 errno = ENOENT;
2106 return -1;
2107 }
2108 memset (&wfd, 0, sizeof (wfd));
2109 wfd.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
2110 wfd.ftCreationTime = utc_base_ft;
2111 wfd.ftLastAccessTime = utc_base_ft;
2112 wfd.ftLastWriteTime = utc_base_ft;
2113 strcpy (wfd.cFileName, name);
2114 }
2115 else
2116 {
2117 if (IS_DIRECTORY_SEP (name[len-1]))
2118 name[len - 1] = 0;
76b3903d
GV
2119
2120 /* (This is hacky, but helps when doing file completions on
2121 network drives.) Optimize by using information available from
2122 active readdir if possible. */
b19cc00c
GV
2123 len = strlen (dir_pathname);
2124 if (IS_DIRECTORY_SEP (dir_pathname[len-1]))
2125 len--;
76b3903d 2126 if (dir_find_handle != INVALID_HANDLE_VALUE
b19cc00c 2127 && strnicmp (name, dir_pathname, len) == 0
76b3903d
GV
2128 && IS_DIRECTORY_SEP (name[len])
2129 && stricmp (name + len + 1, dir_static.d_name) == 0)
480b0c5b 2130 {
76b3903d
GV
2131 /* This was the last entry returned by readdir. */
2132 wfd = dir_find_data;
2133 }
2134 else
2135 {
2136 fh = FindFirstFile (name, &wfd);
2137 if (fh == INVALID_HANDLE_VALUE)
2138 {
2139 errno = ENOENT;
2140 return -1;
2141 }
2142 FindClose (fh);
480b0c5b 2143 }
480b0c5b
GV
2144 }
2145
2146 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
2147 {
2148 buf->st_mode = _S_IFDIR;
2149 buf->st_nlink = 2; /* doesn't really matter */
76b3903d 2150 fake_inode = 0; /* this doesn't either I think */
480b0c5b 2151 }
710ea1b8
RS
2152 else if (!NILP (Vw32_get_true_file_attributes)
2153 /* No access rights required to get info. */
2154 && (fh = CreateFile (name, 0, 0, NULL, OPEN_EXISTING, 0, NULL))
2155 != INVALID_HANDLE_VALUE)
480b0c5b 2156 {
480b0c5b
GV
2157 /* This is more accurate in terms of gettting the correct number
2158 of links, but is quite slow (it is noticable when Emacs is
2159 making a list of file name completions). */
2160 BY_HANDLE_FILE_INFORMATION info;
2161
480b0c5b
GV
2162 if (GetFileInformationByHandle (fh, &info))
2163 {
480b0c5b 2164 buf->st_nlink = info.nNumberOfLinks;
76b3903d
GV
2165 /* Might as well use file index to fake inode values, but this
2166 is not guaranteed to be unique unless we keep a handle open
2167 all the time (even then there are situations where it is
2168 not unique). Reputedly, there are at most 48 bits of info
2169 (on NTFS, presumably less on FAT). */
2170 fake_inode = info.nFileIndexLow ^ info.nFileIndexHigh;
480b0c5b
GV
2171 }
2172 else
2173 {
01f31dfb
AI
2174 buf->st_nlink = 1;
2175 fake_inode = 0;
2176 }
2177
2178 switch (GetFileType (fh))
2179 {
2180 case FILE_TYPE_DISK:
2181 buf->st_mode = _S_IFREG;
2182 break;
2183 case FILE_TYPE_PIPE:
2184 buf->st_mode = _S_IFIFO;
2185 break;
2186 case FILE_TYPE_CHAR:
2187 case FILE_TYPE_UNKNOWN:
2188 default:
2189 buf->st_mode = _S_IFCHR;
480b0c5b 2190 }
01f31dfb 2191 CloseHandle (fh);
76b3903d
GV
2192 }
2193 else
2194 {
2195 /* Don't bother to make this information more accurate. */
480b0c5b
GV
2196 buf->st_mode = _S_IFREG;
2197 buf->st_nlink = 1;
76b3903d
GV
2198 fake_inode = 0;
2199 }
2200
2201#if 0
2202 /* Not sure if there is any point in this. */
2203 if (!NILP (Vw32_generate_fake_inodes))
2204 fake_inode = generate_inode_val (name);
2205 else if (fake_inode == 0)
2206 {
2207 /* For want of something better, try to make everything unique. */
2208 static DWORD gen_num = 0;
2209 fake_inode = ++gen_num;
480b0c5b 2210 }
76b3903d
GV
2211#endif
2212
2213 /* MSVC defines _ino_t to be short; other libc's might not. */
2214 if (sizeof (buf->st_ino) == 2)
2215 buf->st_ino = fake_inode ^ (fake_inode >> 16);
2216 else
2217 buf->st_ino = fake_inode;
480b0c5b
GV
2218
2219 /* consider files to belong to current user */
2220 buf->st_uid = the_passwd.pw_uid;
2221 buf->st_gid = the_passwd.pw_gid;
2222
fbd6baed 2223 /* volume_info is set indirectly by map_w32_filename */
480b0c5b
GV
2224 buf->st_dev = volume_info.serialnum;
2225 buf->st_rdev = volume_info.serialnum;
2226
480b0c5b
GV
2227
2228 buf->st_size = wfd.nFileSizeLow;
2229
2230 /* Convert timestamps to Unix format. */
2231 buf->st_mtime = convert_time (wfd.ftLastWriteTime);
2232 buf->st_atime = convert_time (wfd.ftLastAccessTime);
2233 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
2234 buf->st_ctime = convert_time (wfd.ftCreationTime);
2235 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
2236
2237 /* determine rwx permissions */
2238 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
2239 permission = _S_IREAD;
2240 else
2241 permission = _S_IREAD | _S_IWRITE;
2242
2243 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
2244 permission |= _S_IEXEC;
b3308d2e
KH
2245 else if (is_exec (name))
2246 permission |= _S_IEXEC;
480b0c5b
GV
2247
2248 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
2249
2250 return 0;
2251}
2252
16bb7578
GV
2253/* Provide fstat and utime as well as stat for consistent handling of
2254 file timestamps. */
2255int
2256fstat (int desc, struct stat * buf)
2257{
2258 HANDLE fh = (HANDLE) _get_osfhandle (desc);
2259 BY_HANDLE_FILE_INFORMATION info;
2260 DWORD fake_inode;
2261 int permission;
2262
2263 switch (GetFileType (fh) & ~FILE_TYPE_REMOTE)
2264 {
2265 case FILE_TYPE_DISK:
2266 buf->st_mode = _S_IFREG;
2267 if (!GetFileInformationByHandle (fh, &info))
2268 {
2269 errno = EACCES;
2270 return -1;
2271 }
2272 break;
2273 case FILE_TYPE_PIPE:
2274 buf->st_mode = _S_IFIFO;
2275 goto non_disk;
2276 case FILE_TYPE_CHAR:
2277 case FILE_TYPE_UNKNOWN:
2278 default:
2279 buf->st_mode = _S_IFCHR;
2280 non_disk:
2281 memset (&info, 0, sizeof (info));
2282 info.dwFileAttributes = 0;
2283 info.ftCreationTime = utc_base_ft;
2284 info.ftLastAccessTime = utc_base_ft;
2285 info.ftLastWriteTime = utc_base_ft;
2286 }
2287
2288 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
2289 {
2290 buf->st_mode = _S_IFDIR;
2291 buf->st_nlink = 2; /* doesn't really matter */
2292 fake_inode = 0; /* this doesn't either I think */
2293 }
2294 else
2295 {
2296 buf->st_nlink = info.nNumberOfLinks;
2297 /* Might as well use file index to fake inode values, but this
2298 is not guaranteed to be unique unless we keep a handle open
2299 all the time (even then there are situations where it is
2300 not unique). Reputedly, there are at most 48 bits of info
2301 (on NTFS, presumably less on FAT). */
2302 fake_inode = info.nFileIndexLow ^ info.nFileIndexHigh;
2303 }
2304
2305 /* MSVC defines _ino_t to be short; other libc's might not. */
2306 if (sizeof (buf->st_ino) == 2)
2307 buf->st_ino = fake_inode ^ (fake_inode >> 16);
2308 else
2309 buf->st_ino = fake_inode;
2310
2311 /* consider files to belong to current user */
2312 buf->st_uid = 0;
2313 buf->st_gid = 0;
2314
2315 buf->st_dev = info.dwVolumeSerialNumber;
2316 buf->st_rdev = info.dwVolumeSerialNumber;
2317
2318 buf->st_size = info.nFileSizeLow;
2319
2320 /* Convert timestamps to Unix format. */
2321 buf->st_mtime = convert_time (info.ftLastWriteTime);
2322 buf->st_atime = convert_time (info.ftLastAccessTime);
2323 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
2324 buf->st_ctime = convert_time (info.ftCreationTime);
2325 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
2326
2327 /* determine rwx permissions */
2328 if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
2329 permission = _S_IREAD;
2330 else
2331 permission = _S_IREAD | _S_IWRITE;
2332
2333 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
2334 permission |= _S_IEXEC;
2335 else
2336 {
2337#if 0 /* no way of knowing the filename */
2338 char * p = strrchr (name, '.');
2339 if (p != NULL &&
2340 (stricmp (p, ".exe") == 0 ||
2341 stricmp (p, ".com") == 0 ||
2342 stricmp (p, ".bat") == 0 ||
2343 stricmp (p, ".cmd") == 0))
2344 permission |= _S_IEXEC;
2345#endif
2346 }
2347
2348 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
2349
2350 return 0;
2351}
2352
2353int
2354utime (const char *name, struct utimbuf *times)
2355{
2356 struct utimbuf deftime;
2357 HANDLE fh;
2358 FILETIME mtime;
2359 FILETIME atime;
2360
2361 if (times == NULL)
2362 {
2363 deftime.modtime = deftime.actime = time (NULL);
2364 times = &deftime;
2365 }
2366
2367 /* Need write access to set times. */
2368 fh = CreateFile (name, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
2369 0, OPEN_EXISTING, 0, NULL);
2370 if (fh)
2371 {
2372 convert_from_time_t (times->actime, &atime);
2373 convert_from_time_t (times->modtime, &mtime);
2374 if (!SetFileTime (fh, NULL, &atime, &mtime))
2375 {
2376 CloseHandle (fh);
2377 errno = EACCES;
2378 return -1;
2379 }
2380 CloseHandle (fh);
2381 }
2382 else
2383 {
2384 errno = EINVAL;
2385 return -1;
2386 }
2387 return 0;
2388}
2389
480b0c5b
GV
2390#ifdef HAVE_SOCKETS
2391
2392/* Wrappers for winsock functions to map between our file descriptors
2393 and winsock's handles; also set h_errno for convenience.
2394
2395 To allow Emacs to run on systems which don't have winsock support
2396 installed, we dynamically link to winsock on startup if present, and
2397 otherwise provide the minimum necessary functionality
2398 (eg. gethostname). */
2399
2400/* function pointers for relevant socket functions */
2401int (PASCAL *pfn_WSAStartup) (WORD wVersionRequired, LPWSADATA lpWSAData);
2402void (PASCAL *pfn_WSASetLastError) (int iError);
2403int (PASCAL *pfn_WSAGetLastError) (void);
2404int (PASCAL *pfn_socket) (int af, int type, int protocol);
2405int (PASCAL *pfn_bind) (SOCKET s, const struct sockaddr *addr, int namelen);
2406int (PASCAL *pfn_connect) (SOCKET s, const struct sockaddr *addr, int namelen);
2407int (PASCAL *pfn_ioctlsocket) (SOCKET s, long cmd, u_long *argp);
2408int (PASCAL *pfn_recv) (SOCKET s, char * buf, int len, int flags);
2409int (PASCAL *pfn_send) (SOCKET s, const char * buf, int len, int flags);
2410int (PASCAL *pfn_closesocket) (SOCKET s);
2411int (PASCAL *pfn_shutdown) (SOCKET s, int how);
2412int (PASCAL *pfn_WSACleanup) (void);
2413
2414u_short (PASCAL *pfn_htons) (u_short hostshort);
2415u_short (PASCAL *pfn_ntohs) (u_short netshort);
2416unsigned long (PASCAL *pfn_inet_addr) (const char * cp);
2417int (PASCAL *pfn_gethostname) (char * name, int namelen);
2418struct hostent * (PASCAL *pfn_gethostbyname) (const char * name);
2419struct servent * (PASCAL *pfn_getservbyname) (const char * name, const char * proto);
f1614061
RS
2420
2421/* SetHandleInformation is only needed to make sockets non-inheritable. */
2422BOOL (WINAPI *pfn_SetHandleInformation) (HANDLE object, DWORD mask, DWORD flags);
2423#ifndef HANDLE_FLAG_INHERIT
2424#define HANDLE_FLAG_INHERIT 1
2425#endif
480b0c5b 2426
f249a012
RS
2427HANDLE winsock_lib;
2428static int winsock_inuse;
480b0c5b 2429
f249a012 2430BOOL
480b0c5b
GV
2431term_winsock (void)
2432{
f249a012 2433 if (winsock_lib != NULL && winsock_inuse == 0)
480b0c5b 2434 {
f249a012
RS
2435 /* Not sure what would cause WSAENETDOWN, or even if it can happen
2436 after WSAStartup returns successfully, but it seems reasonable
2437 to allow unloading winsock anyway in that case. */
2438 if (pfn_WSACleanup () == 0 ||
2439 pfn_WSAGetLastError () == WSAENETDOWN)
2440 {
2441 if (FreeLibrary (winsock_lib))
2442 winsock_lib = NULL;
2443 return TRUE;
2444 }
480b0c5b 2445 }
f249a012 2446 return FALSE;
480b0c5b
GV
2447}
2448
f249a012
RS
2449BOOL
2450init_winsock (int load_now)
480b0c5b
GV
2451{
2452 WSADATA winsockData;
2453
f249a012
RS
2454 if (winsock_lib != NULL)
2455 return TRUE;
f1614061
RS
2456
2457 pfn_SetHandleInformation = NULL;
2458 pfn_SetHandleInformation
2459 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
2460 "SetHandleInformation");
2461
480b0c5b
GV
2462 winsock_lib = LoadLibrary ("wsock32.dll");
2463
2464 if (winsock_lib != NULL)
2465 {
2466 /* dynamically link to socket functions */
2467
2468#define LOAD_PROC(fn) \
2469 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
2470 goto fail;
2471
2472 LOAD_PROC( WSAStartup );
2473 LOAD_PROC( WSASetLastError );
2474 LOAD_PROC( WSAGetLastError );
2475 LOAD_PROC( socket );
2476 LOAD_PROC( bind );
2477 LOAD_PROC( connect );
2478 LOAD_PROC( ioctlsocket );
2479 LOAD_PROC( recv );
2480 LOAD_PROC( send );
2481 LOAD_PROC( closesocket );
2482 LOAD_PROC( shutdown );
2483 LOAD_PROC( htons );
2484 LOAD_PROC( ntohs );
2485 LOAD_PROC( inet_addr );
2486 LOAD_PROC( gethostname );
2487 LOAD_PROC( gethostbyname );
2488 LOAD_PROC( getservbyname );
2489 LOAD_PROC( WSACleanup );
2490
f249a012
RS
2491#undef LOAD_PROC
2492
480b0c5b
GV
2493 /* specify version 1.1 of winsock */
2494 if (pfn_WSAStartup (0x101, &winsockData) == 0)
2495 {
f249a012
RS
2496 if (winsockData.wVersion != 0x101)
2497 goto fail;
2498
2499 if (!load_now)
2500 {
2501 /* Report that winsock exists and is usable, but leave
2502 socket functions disabled. I am assuming that calling
2503 WSAStartup does not require any network interaction,
2504 and in particular does not cause or require a dial-up
2505 connection to be established. */
2506
2507 pfn_WSACleanup ();
2508 FreeLibrary (winsock_lib);
2509 winsock_lib = NULL;
2510 }
2511 winsock_inuse = 0;
2512 return TRUE;
480b0c5b
GV
2513 }
2514
2515 fail:
2516 FreeLibrary (winsock_lib);
f249a012 2517 winsock_lib = NULL;
480b0c5b 2518 }
f249a012
RS
2519
2520 return FALSE;
480b0c5b
GV
2521}
2522
2523
2524int h_errno = 0;
2525
2526/* function to set h_errno for compatability; map winsock error codes to
2527 normal system codes where they overlap (non-overlapping definitions
2528 are already in <sys/socket.h> */
2529static void set_errno ()
2530{
f249a012 2531 if (winsock_lib == NULL)
480b0c5b
GV
2532 h_errno = EINVAL;
2533 else
2534 h_errno = pfn_WSAGetLastError ();
2535
2536 switch (h_errno)
2537 {
2538 case WSAEACCES: h_errno = EACCES; break;
2539 case WSAEBADF: h_errno = EBADF; break;
2540 case WSAEFAULT: h_errno = EFAULT; break;
2541 case WSAEINTR: h_errno = EINTR; break;
2542 case WSAEINVAL: h_errno = EINVAL; break;
2543 case WSAEMFILE: h_errno = EMFILE; break;
2544 case WSAENAMETOOLONG: h_errno = ENAMETOOLONG; break;
2545 case WSAENOTEMPTY: h_errno = ENOTEMPTY; break;
2546 }
2547 errno = h_errno;
2548}
2549
2550static void check_errno ()
2551{
f249a012 2552 if (h_errno == 0 && winsock_lib != NULL)
480b0c5b
GV
2553 pfn_WSASetLastError (0);
2554}
2555
d8fcc1b9
AI
2556/* Extend strerror to handle the winsock-specific error codes. */
2557struct {
2558 int errnum;
2559 char * msg;
2560} _wsa_errlist[] = {
2561 WSAEINTR , "Interrupted function call",
2562 WSAEBADF , "Bad file descriptor",
2563 WSAEACCES , "Permission denied",
2564 WSAEFAULT , "Bad address",
2565 WSAEINVAL , "Invalid argument",
2566 WSAEMFILE , "Too many open files",
2567
2568 WSAEWOULDBLOCK , "Resource temporarily unavailable",
2569 WSAEINPROGRESS , "Operation now in progress",
2570 WSAEALREADY , "Operation already in progress",
2571 WSAENOTSOCK , "Socket operation on non-socket",
2572 WSAEDESTADDRREQ , "Destination address required",
2573 WSAEMSGSIZE , "Message too long",
2574 WSAEPROTOTYPE , "Protocol wrong type for socket",
2575 WSAENOPROTOOPT , "Bad protocol option",
2576 WSAEPROTONOSUPPORT , "Protocol not supported",
2577 WSAESOCKTNOSUPPORT , "Socket type not supported",
2578 WSAEOPNOTSUPP , "Operation not supported",
2579 WSAEPFNOSUPPORT , "Protocol family not supported",
2580 WSAEAFNOSUPPORT , "Address family not supported by protocol family",
2581 WSAEADDRINUSE , "Address already in use",
2582 WSAEADDRNOTAVAIL , "Cannot assign requested address",
2583 WSAENETDOWN , "Network is down",
2584 WSAENETUNREACH , "Network is unreachable",
2585 WSAENETRESET , "Network dropped connection on reset",
2586 WSAECONNABORTED , "Software caused connection abort",
2587 WSAECONNRESET , "Connection reset by peer",
2588 WSAENOBUFS , "No buffer space available",
2589 WSAEISCONN , "Socket is already connected",
2590 WSAENOTCONN , "Socket is not connected",
2591 WSAESHUTDOWN , "Cannot send after socket shutdown",
2592 WSAETOOMANYREFS , "Too many references", /* not sure */
2593 WSAETIMEDOUT , "Connection timed out",
2594 WSAECONNREFUSED , "Connection refused",
2595 WSAELOOP , "Network loop", /* not sure */
2596 WSAENAMETOOLONG , "Name is too long",
2597 WSAEHOSTDOWN , "Host is down",
2598 WSAEHOSTUNREACH , "No route to host",
2599 WSAENOTEMPTY , "Buffer not empty", /* not sure */
2600 WSAEPROCLIM , "Too many processes",
2601 WSAEUSERS , "Too many users", /* not sure */
2602 WSAEDQUOT , "Double quote in host name", /* really not sure */
2603 WSAESTALE , "Data is stale", /* not sure */
2604 WSAEREMOTE , "Remote error", /* not sure */
2605
2606 WSASYSNOTREADY , "Network subsystem is unavailable",
2607 WSAVERNOTSUPPORTED , "WINSOCK.DLL version out of range",
2608 WSANOTINITIALISED , "Winsock not initialized successfully",
2609 WSAEDISCON , "Graceful shutdown in progress",
2610#ifdef WSAENOMORE
2611 WSAENOMORE , "No more operations allowed", /* not sure */
2612 WSAECANCELLED , "Operation cancelled", /* not sure */
2613 WSAEINVALIDPROCTABLE , "Invalid procedure table from service provider",
2614 WSAEINVALIDPROVIDER , "Invalid service provider version number",
2615 WSAEPROVIDERFAILEDINIT , "Unable to initialize a service provider",
2616 WSASYSCALLFAILURE , "System call failured",
2617 WSASERVICE_NOT_FOUND , "Service not found", /* not sure */
2618 WSATYPE_NOT_FOUND , "Class type not found",
2619 WSA_E_NO_MORE , "No more resources available", /* really not sure */
2620 WSA_E_CANCELLED , "Operation already cancelled", /* really not sure */
2621 WSAEREFUSED , "Operation refused", /* not sure */
2622#endif
2623
2624 WSAHOST_NOT_FOUND , "Host not found",
2625 WSATRY_AGAIN , "Authoritative host not found during name lookup",
2626 WSANO_RECOVERY , "Non-recoverable error during name lookup",
2627 WSANO_DATA , "Valid name, no data record of requested type",
2628
2629 -1, NULL
2630};
2631
2632char *
2633sys_strerror(int error_no)
2634{
2635 int i;
2636 static char unknown_msg[40];
2637
a302c7ae
AI
2638 if (error_no >= 0 && error_no < sys_nerr)
2639 return sys_errlist[error_no];
d8fcc1b9
AI
2640
2641 for (i = 0; _wsa_errlist[i].errnum >= 0; i++)
2642 if (_wsa_errlist[i].errnum == error_no)
2643 return _wsa_errlist[i].msg;
2644
2645 sprintf(unknown_msg, "Unidentified error: %d", error_no);
2646 return unknown_msg;
2647}
2648
480b0c5b
GV
2649/* [andrewi 3-May-96] I've had conflicting results using both methods,
2650 but I believe the method of keeping the socket handle separate (and
2651 insuring it is not inheritable) is the correct one. */
2652
2653//#define SOCK_REPLACE_HANDLE
2654
2655#ifdef SOCK_REPLACE_HANDLE
2656#define SOCK_HANDLE(fd) ((SOCKET) _get_osfhandle (fd))
2657#else
2658#define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
2659#endif
2660
2661int
2662sys_socket(int af, int type, int protocol)
2663{
2664 int fd;
2665 long s;
2666 child_process * cp;
2667
f249a012 2668 if (winsock_lib == NULL)
480b0c5b
GV
2669 {
2670 h_errno = ENETDOWN;
2671 return INVALID_SOCKET;
2672 }
2673
2674 check_errno ();
2675
2676 /* call the real socket function */
2677 s = (long) pfn_socket (af, type, protocol);
2678
2679 if (s != INVALID_SOCKET)
2680 {
2681 /* Although under NT 3.5 _open_osfhandle will accept a socket
2682 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
2683 that does not work under NT 3.1. However, we can get the same
2684 effect by using a backdoor function to replace an existing
2685 descriptor handle with the one we want. */
2686
2687 /* allocate a file descriptor (with appropriate flags) */
2688 fd = _open ("NUL:", _O_RDWR);
2689 if (fd >= 0)
2690 {
2691#ifdef SOCK_REPLACE_HANDLE
2692 /* now replace handle to NUL with our socket handle */
2693 CloseHandle ((HANDLE) _get_osfhandle (fd));
2694 _free_osfhnd (fd);
2695 _set_osfhnd (fd, s);
2696 /* setmode (fd, _O_BINARY); */
2697#else
ca149beb
AI
2698 /* Make a non-inheritable copy of the socket handle. Note
2699 that it is possible that sockets aren't actually kernel
2700 handles, which appears to be the case on Windows 9x when
2701 the MS Proxy winsock client is installed. */
480b0c5b 2702 {
f1614061
RS
2703 /* Apparently there is a bug in NT 3.51 with some service
2704 packs, which prevents using DuplicateHandle to make a
2705 socket handle non-inheritable (causes WSACleanup to
2706 hang). The work-around is to use SetHandleInformation
2707 instead if it is available and implemented. */
ca149beb
AI
2708 if (pfn_SetHandleInformation)
2709 {
2710 pfn_SetHandleInformation ((HANDLE) s, HANDLE_FLAG_INHERIT, 0);
2711 }
2712 else
f1614061 2713 {
ca149beb
AI
2714 HANDLE parent = GetCurrentProcess ();
2715 HANDLE new_s = INVALID_HANDLE_VALUE;
2716
2717 if (DuplicateHandle (parent,
2718 (HANDLE) s,
2719 parent,
2720 &new_s,
2721 0,
2722 FALSE,
2723 DUPLICATE_SAME_ACCESS))
2724 {
2725 /* It is possible that DuplicateHandle succeeds even
2726 though the socket wasn't really a kernel handle,
2727 because a real handle has the same value. So
2728 test whether the new handle really is a socket. */
2729 long nonblocking = 0;
2730 if (pfn_ioctlsocket ((SOCKET) new_s, FIONBIO, &nonblocking) == 0)
2731 {
2732 pfn_closesocket (s);
2733 s = (SOCKET) new_s;
2734 }
2735 else
2736 {
2737 CloseHandle (new_s);
2738 }
2739 }
f1614061 2740 }
480b0c5b 2741 }
ca149beb 2742 fd_info[fd].hnd = (HANDLE) s;
480b0c5b
GV
2743#endif
2744
2745 /* set our own internal flags */
2746 fd_info[fd].flags = FILE_SOCKET | FILE_BINARY | FILE_READ | FILE_WRITE;
2747
2748 cp = new_child ();
2749 if (cp)
2750 {
2751 cp->fd = fd;
2752 cp->status = STATUS_READ_ACKNOWLEDGED;
2753
2754 /* attach child_process to fd_info */
2755 if (fd_info[ fd ].cp != NULL)
2756 {
2757 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd));
2758 abort ();
2759 }
2760
2761 fd_info[ fd ].cp = cp;
2762
2763 /* success! */
f249a012 2764 winsock_inuse++; /* count open sockets */
480b0c5b
GV
2765 return fd;
2766 }
2767
2768 /* clean up */
2769 _close (fd);
2770 }
2771 pfn_closesocket (s);
2772 h_errno = EMFILE;
2773 }
2774 set_errno ();
2775
2776 return -1;
2777}
2778
2779
2780int
2781sys_bind (int s, const struct sockaddr * addr, int namelen)
2782{
f249a012 2783 if (winsock_lib == NULL)
480b0c5b
GV
2784 {
2785 h_errno = ENOTSOCK;
2786 return SOCKET_ERROR;
2787 }
2788
2789 check_errno ();
2790 if (fd_info[s].flags & FILE_SOCKET)
2791 {
2792 int rc = pfn_bind (SOCK_HANDLE (s), addr, namelen);
2793 if (rc == SOCKET_ERROR)
2794 set_errno ();
2795 return rc;
2796 }
2797 h_errno = ENOTSOCK;
2798 return SOCKET_ERROR;
2799}
2800
2801
2802int
2803sys_connect (int s, const struct sockaddr * name, int namelen)
2804{
f249a012 2805 if (winsock_lib == NULL)
480b0c5b
GV
2806 {
2807 h_errno = ENOTSOCK;
2808 return SOCKET_ERROR;
2809 }
2810
2811 check_errno ();
2812 if (fd_info[s].flags & FILE_SOCKET)
2813 {
2814 int rc = pfn_connect (SOCK_HANDLE (s), name, namelen);
2815 if (rc == SOCKET_ERROR)
2816 set_errno ();
2817 return rc;
2818 }
2819 h_errno = ENOTSOCK;
2820 return SOCKET_ERROR;
2821}
2822
2823u_short
2824sys_htons (u_short hostshort)
2825{
f249a012 2826 return (winsock_lib != NULL) ?
480b0c5b
GV
2827 pfn_htons (hostshort) : hostshort;
2828}
2829
2830u_short
2831sys_ntohs (u_short netshort)
2832{
f249a012 2833 return (winsock_lib != NULL) ?
480b0c5b
GV
2834 pfn_ntohs (netshort) : netshort;
2835}
2836
2837unsigned long
2838sys_inet_addr (const char * cp)
2839{
f249a012 2840 return (winsock_lib != NULL) ?
480b0c5b
GV
2841 pfn_inet_addr (cp) : INADDR_NONE;
2842}
2843
2844int
2845sys_gethostname (char * name, int namelen)
2846{
f249a012 2847 if (winsock_lib != NULL)
480b0c5b
GV
2848 return pfn_gethostname (name, namelen);
2849
2850 if (namelen > MAX_COMPUTERNAME_LENGTH)
a302c7ae 2851 return !GetComputerName (name, (DWORD *)&namelen);
480b0c5b
GV
2852
2853 h_errno = EFAULT;
2854 return SOCKET_ERROR;
2855}
2856
2857struct hostent *
2858sys_gethostbyname(const char * name)
2859{
2860 struct hostent * host;
2861
f249a012 2862 if (winsock_lib == NULL)
480b0c5b
GV
2863 {
2864 h_errno = ENETDOWN;
2865 return NULL;
2866 }
2867
2868 check_errno ();
2869 host = pfn_gethostbyname (name);
2870 if (!host)
2871 set_errno ();
2872 return host;
2873}
2874
2875struct servent *
2876sys_getservbyname(const char * name, const char * proto)
2877{
2878 struct servent * serv;
2879
f249a012 2880 if (winsock_lib == NULL)
480b0c5b
GV
2881 {
2882 h_errno = ENETDOWN;
2883 return NULL;
2884 }
2885
2886 check_errno ();
2887 serv = pfn_getservbyname (name, proto);
2888 if (!serv)
2889 set_errno ();
2890 return serv;
2891}
2892
380961a6
GV
2893int
2894sys_shutdown (int s, int how)
2895{
380961a6
GV
2896 if (winsock_lib == NULL)
2897 {
2898 h_errno = ENETDOWN;
2899 return SOCKET_ERROR;
2900 }
2901
2902 check_errno ();
2903 if (fd_info[s].flags & FILE_SOCKET)
2904 {
2905 int rc = pfn_shutdown (SOCK_HANDLE (s), how);
2906 if (rc == SOCKET_ERROR)
2907 set_errno ();
2908 return rc;
2909 }
2910 h_errno = ENOTSOCK;
2911 return SOCKET_ERROR;
2912}
2913
480b0c5b
GV
2914#endif /* HAVE_SOCKETS */
2915
2916
2917/* Shadow main io functions: we need to handle pipes and sockets more
2918 intelligently, and implement non-blocking mode as well. */
2919
2920int
2921sys_close (int fd)
2922{
2923 int rc;
2924
2925 if (fd < 0 || fd >= MAXDESC)
2926 {
2927 errno = EBADF;
2928 return -1;
2929 }
2930
2931 if (fd_info[fd].cp)
2932 {
2933 child_process * cp = fd_info[fd].cp;
2934
2935 fd_info[fd].cp = NULL;
2936
2937 if (CHILD_ACTIVE (cp))
2938 {
2939 /* if last descriptor to active child_process then cleanup */
2940 int i;
2941 for (i = 0; i < MAXDESC; i++)
2942 {
2943 if (i == fd)
2944 continue;
2945 if (fd_info[i].cp == cp)
2946 break;
2947 }
2948 if (i == MAXDESC)
2949 {
f249a012 2950#ifdef HAVE_SOCKETS
480b0c5b
GV
2951 if (fd_info[fd].flags & FILE_SOCKET)
2952 {
f249a012
RS
2953#ifndef SOCK_REPLACE_HANDLE
2954 if (winsock_lib == NULL) abort ();
480b0c5b
GV
2955
2956 pfn_shutdown (SOCK_HANDLE (fd), 2);
2957 rc = pfn_closesocket (SOCK_HANDLE (fd));
f249a012
RS
2958#endif
2959 winsock_inuse--; /* count open sockets */
480b0c5b
GV
2960 }
2961#endif
2962 delete_child (cp);
2963 }
2964 }
2965 }
2966
2967 /* Note that sockets do not need special treatment here (at least on
e9e23e23 2968 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
480b0c5b
GV
2969 closesocket is equivalent to CloseHandle, which is to be expected
2970 because socket handles are fully fledged kernel handles. */
2971 rc = _close (fd);
2972
2973 if (rc == 0)
2974 fd_info[fd].flags = 0;
2975
2976 return rc;
2977}
2978
2979int
2980sys_dup (int fd)
2981{
2982 int new_fd;
2983
2984 new_fd = _dup (fd);
2985 if (new_fd >= 0)
2986 {
2987 /* duplicate our internal info as well */
2988 fd_info[new_fd] = fd_info[fd];
2989 }
2990 return new_fd;
2991}
2992
2993
2994int
2995sys_dup2 (int src, int dst)
2996{
2997 int rc;
2998
2999 if (dst < 0 || dst >= MAXDESC)
3000 {
3001 errno = EBADF;
3002 return -1;
3003 }
3004
3005 /* make sure we close the destination first if it's a pipe or socket */
3006 if (src != dst && fd_info[dst].flags != 0)
3007 sys_close (dst);
3008
3009 rc = _dup2 (src, dst);
3010 if (rc == 0)
3011 {
3012 /* duplicate our internal info as well */
3013 fd_info[dst] = fd_info[src];
3014 }
3015 return rc;
3016}
3017
480b0c5b
GV
3018/* Unix pipe() has only one arg */
3019int
3020sys_pipe (int * phandles)
3021{
3022 int rc;
3023 unsigned flags;
480b0c5b 3024
76b3903d
GV
3025 /* make pipe handles non-inheritable; when we spawn a child, we
3026 replace the relevant handle with an inheritable one. Also put
3027 pipes into binary mode; we will do text mode translation ourselves
3028 if required. */
3029 rc = _pipe (phandles, 0, _O_NOINHERIT | _O_BINARY);
480b0c5b
GV
3030
3031 if (rc == 0)
3032 {
7664e306 3033 flags = FILE_PIPE | FILE_READ | FILE_BINARY;
480b0c5b
GV
3034 fd_info[phandles[0]].flags = flags;
3035
7664e306 3036 flags = FILE_PIPE | FILE_WRITE | FILE_BINARY;
480b0c5b
GV
3037 fd_info[phandles[1]].flags = flags;
3038 }
3039
3040 return rc;
3041}
3042
f7554349 3043/* From ntproc.c */
fbd6baed 3044extern Lisp_Object Vw32_pipe_read_delay;
f7554349 3045
480b0c5b
GV
3046/* Function to do blocking read of one byte, needed to implement
3047 select. It is only allowed on sockets and pipes. */
3048int
3049_sys_read_ahead (int fd)
3050{
3051 child_process * cp;
3052 int rc;
3053
3054 if (fd < 0 || fd >= MAXDESC)
3055 return STATUS_READ_ERROR;
3056
3057 cp = fd_info[fd].cp;
3058
3059 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
3060 return STATUS_READ_ERROR;
3061
3062 if ((fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET)) == 0
3063 || (fd_info[fd].flags & FILE_READ) == 0)
3064 {
3065 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe or socket!\n", fd));
3066 abort ();
3067 }
3068
3069 cp->status = STATUS_READ_IN_PROGRESS;
3070
3071 if (fd_info[fd].flags & FILE_PIPE)
f7554349 3072 {
f7554349
KH
3073 rc = _read (fd, &cp->chr, sizeof (char));
3074
3075 /* Give subprocess time to buffer some more output for us before
e9e23e23 3076 reporting that input is available; we need this because Windows 95
f7554349
KH
3077 connects DOS programs to pipes by making the pipe appear to be
3078 the normal console stdout - as a result most DOS programs will
3079 write to stdout without buffering, ie. one character at a
fbd6baed 3080 time. Even some W32 programs do this - "dir" in a command
f7554349
KH
3081 shell on NT is very slow if we don't do this. */
3082 if (rc > 0)
3083 {
fbd6baed 3084 int wait = XINT (Vw32_pipe_read_delay);
f7554349
KH
3085
3086 if (wait > 0)
3087 Sleep (wait);
3088 else if (wait < 0)
3089 while (++wait <= 0)
3090 /* Yield remainder of our time slice, effectively giving a
3091 temporary priority boost to the child process. */
3092 Sleep (0);
3093 }
3094 }
480b0c5b
GV
3095#ifdef HAVE_SOCKETS
3096 else if (fd_info[fd].flags & FILE_SOCKET)
3097 rc = pfn_recv (SOCK_HANDLE (fd), &cp->chr, sizeof (char), 0);
3098#endif
3099
3100 if (rc == sizeof (char))
3101 cp->status = STATUS_READ_SUCCEEDED;
3102 else
3103 cp->status = STATUS_READ_FAILED;
3104
3105 return cp->status;
3106}
3107
3108int
3109sys_read (int fd, char * buffer, unsigned int count)
3110{
3111 int nchars;
480b0c5b
GV
3112 int to_read;
3113 DWORD waiting;
76b3903d 3114 char * orig_buffer = buffer;
480b0c5b
GV
3115
3116 if (fd < 0 || fd >= MAXDESC)
3117 {
3118 errno = EBADF;
3119 return -1;
3120 }
3121
3122 if (fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET))
3123 {
3124 child_process *cp = fd_info[fd].cp;
3125
3126 if ((fd_info[fd].flags & FILE_READ) == 0)
3127 {
3128 errno = EBADF;
3129 return -1;
3130 }
3131
76b3903d
GV
3132 nchars = 0;
3133
3134 /* re-read CR carried over from last read */
3135 if (fd_info[fd].flags & FILE_LAST_CR)
3136 {
3137 if (fd_info[fd].flags & FILE_BINARY) abort ();
3138 *buffer++ = 0x0d;
3139 count--;
3140 nchars++;
f52eb3ef 3141 fd_info[fd].flags &= ~FILE_LAST_CR;
76b3903d
GV
3142 }
3143
480b0c5b
GV
3144 /* presence of a child_process structure means we are operating in
3145 non-blocking mode - otherwise we just call _read directly.
3146 Note that the child_process structure might be missing because
3147 reap_subprocess has been called; in this case the pipe is
3148 already broken, so calling _read on it is okay. */
3149 if (cp)
3150 {
3151 int current_status = cp->status;
3152
3153 switch (current_status)
3154 {
3155 case STATUS_READ_FAILED:
3156 case STATUS_READ_ERROR:
f52eb3ef
GV
3157 /* report normal EOF if nothing in buffer */
3158 if (nchars <= 0)
3159 fd_info[fd].flags |= FILE_AT_EOF;
3160 return nchars;
480b0c5b
GV
3161
3162 case STATUS_READ_READY:
3163 case STATUS_READ_IN_PROGRESS:
3164 DebPrint (("sys_read called when read is in progress\n"));
3165 errno = EWOULDBLOCK;
3166 return -1;
3167
3168 case STATUS_READ_SUCCEEDED:
3169 /* consume read-ahead char */
3170 *buffer++ = cp->chr;
3171 count--;
76b3903d 3172 nchars++;
480b0c5b
GV
3173 cp->status = STATUS_READ_ACKNOWLEDGED;
3174 ResetEvent (cp->char_avail);
3175
3176 case STATUS_READ_ACKNOWLEDGED:
3177 break;
3178
3179 default:
3180 DebPrint (("sys_read: bad status %d\n", current_status));
3181 errno = EBADF;
3182 return -1;
3183 }
3184
3185 if (fd_info[fd].flags & FILE_PIPE)
3186 {
3187 PeekNamedPipe ((HANDLE) _get_osfhandle (fd), NULL, 0, NULL, &waiting, NULL);
3188 to_read = min (waiting, (DWORD) count);
f52eb3ef
GV
3189
3190 if (to_read > 0)
3191 nchars += _read (fd, buffer, to_read);
480b0c5b
GV
3192 }
3193#ifdef HAVE_SOCKETS
3194 else /* FILE_SOCKET */
3195 {
f249a012 3196 if (winsock_lib == NULL) abort ();
480b0c5b
GV
3197
3198 /* do the equivalent of a non-blocking read */
3199 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONREAD, &waiting);
76b3903d 3200 if (waiting == 0 && nchars == 0)
480b0c5b
GV
3201 {
3202 h_errno = errno = EWOULDBLOCK;
3203 return -1;
3204 }
3205
480b0c5b
GV
3206 if (waiting)
3207 {
3208 /* always use binary mode for sockets */
76b3903d
GV
3209 int res = pfn_recv (SOCK_HANDLE (fd), buffer, count, 0);
3210 if (res == SOCKET_ERROR)
480b0c5b
GV
3211 {
3212 DebPrint(("sys_read.recv failed with error %d on socket %ld\n",
3213 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
76b3903d
GV
3214 set_errno ();
3215 return -1;
480b0c5b 3216 }
76b3903d 3217 nchars += res;
480b0c5b
GV
3218 }
3219 }
3220#endif
3221 }
3222 else
f52eb3ef
GV
3223 {
3224 int nread = _read (fd, buffer, count);
3225 if (nread >= 0)
3226 nchars += nread;
3227 else if (nchars == 0)
3228 nchars = nread;
3229 }
76b3903d 3230
f52eb3ef
GV
3231 if (nchars <= 0)
3232 fd_info[fd].flags |= FILE_AT_EOF;
76b3903d 3233 /* Perform text mode translation if required. */
f52eb3ef 3234 else if ((fd_info[fd].flags & FILE_BINARY) == 0)
76b3903d
GV
3235 {
3236 nchars = crlf_to_lf (nchars, orig_buffer);
3237 /* If buffer contains only CR, return that. To be absolutely
3238 sure we should attempt to read the next char, but in
3239 practice a CR to be followed by LF would not appear by
3240 itself in the buffer. */
3241 if (nchars > 1 && orig_buffer[nchars - 1] == 0x0d)
3242 {
3243 fd_info[fd].flags |= FILE_LAST_CR;
3244 nchars--;
3245 }
76b3903d 3246 }
480b0c5b
GV
3247 }
3248 else
3249 nchars = _read (fd, buffer, count);
3250
76b3903d 3251 return nchars;
480b0c5b
GV
3252}
3253
3254/* For now, don't bother with a non-blocking mode */
3255int
3256sys_write (int fd, const void * buffer, unsigned int count)
3257{
3258 int nchars;
3259
3260 if (fd < 0 || fd >= MAXDESC)
3261 {
3262 errno = EBADF;
3263 return -1;
3264 }
3265
3266 if (fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET))
76b3903d
GV
3267 {
3268 if ((fd_info[fd].flags & FILE_WRITE) == 0)
3269 {
3270 errno = EBADF;
3271 return -1;
3272 }
3273
3274 /* Perform text mode translation if required. */
3275 if ((fd_info[fd].flags & FILE_BINARY) == 0)
3276 {
3277 char * tmpbuf = alloca (count * 2);
3278 unsigned char * src = (void *)buffer;
3279 unsigned char * dst = tmpbuf;
3280 int nbytes = count;
3281
3282 while (1)
3283 {
3284 unsigned char *next;
3285 /* copy next line or remaining bytes */
3286 next = _memccpy (dst, src, '\n', nbytes);
3287 if (next)
3288 {
3289 /* copied one line ending with '\n' */
3290 int copied = next - dst;
3291 nbytes -= copied;
3292 src += copied;
3293 /* insert '\r' before '\n' */
3294 next[-1] = '\r';
3295 next[0] = '\n';
3296 dst = next + 1;
3297 count++;
3298 }
3299 else
3300 /* copied remaining partial line -> now finished */
3301 break;
3302 }
3303 buffer = tmpbuf;
3304 }
3305 }
3306
480b0c5b
GV
3307#ifdef HAVE_SOCKETS
3308 if (fd_info[fd].flags & FILE_SOCKET)
3309 {
f249a012 3310 if (winsock_lib == NULL) abort ();
480b0c5b
GV
3311 nchars = pfn_send (SOCK_HANDLE (fd), buffer, count, 0);
3312 if (nchars == SOCKET_ERROR)
3313 {
3314 DebPrint(("sys_read.send failed with error %d on socket %ld\n",
3315 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
3316 set_errno ();
3317 }
3318 }
3319 else
3320#endif
3321 nchars = _write (fd, buffer, count);
3322
3323 return nchars;
3324}
3325
f52eb3ef
GV
3326static void
3327check_windows_init_file ()
3328{
3329 extern int noninteractive, inhibit_window_system;
3330
3331 /* A common indication that Emacs is not installed properly is when
3332 it cannot find the Windows installation file. If this file does
3333 not exist in the expected place, tell the user. */
3334
d54abccd
GV
3335 if (!noninteractive && !inhibit_window_system)
3336 {
3337 extern Lisp_Object Vwindow_system, Vload_path, Qfile_exists_p;
a0b9c838 3338 Lisp_Object objs[2];
96ef7d42 3339 Lisp_Object full_load_path;
d54abccd
GV
3340 Lisp_Object init_file;
3341 int fd;
f52eb3ef 3342
a0b9c838
GV
3343 objs[0] = Vload_path;
3344 objs[1] = decode_env_path (0, (getenv ("EMACSLOADPATH")));
3345 full_load_path = Fappend (2, objs);
d54abccd 3346 init_file = build_string ("term/w32-win");
c0ec53ad 3347 fd = openp (full_load_path, init_file, Vload_suffixes, NULL, 0);
d54abccd
GV
3348 if (fd < 0)
3349 {
96ef7d42 3350 Lisp_Object load_path_print = Fprin1_to_string (full_load_path, Qnil);
d54abccd
GV
3351 char *init_file_name = XSTRING (init_file)->data;
3352 char *load_path = XSTRING (load_path_print)->data;
3353 char *buffer = alloca (1024);
3354
3355 sprintf (buffer,
3356 "The Emacs Windows initialization file \"%s.el\" "
3357 "could not be found in your Emacs installation. "
3358 "Emacs checked the following directories for this file:\n"
3359 "\n%s\n\n"
3360 "When Emacs cannot find this file, it usually means that it "
3361 "was not installed properly, or its distribution file was "
3362 "not unpacked properly.\nSee the README.W32 file in the "
3363 "top-level Emacs directory for more information.",
3364 init_file_name, load_path);
3365 MessageBox (NULL,
3366 buffer,
3367 "Emacs Abort Dialog",
3368 MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
f52eb3ef
GV
3369 /* Use the low-level Emacs abort. */
3370#undef abort
d54abccd
GV
3371 abort ();
3372 }
3373 else
3374 {
a302c7ae 3375 _close (fd);
d54abccd 3376 }
f52eb3ef 3377 }
f52eb3ef 3378}
480b0c5b
GV
3379
3380void
3381term_ntproc ()
3382{
3383#ifdef HAVE_SOCKETS
3384 /* shutdown the socket interface if necessary */
3385 term_winsock ();
3386#endif
3387}
3388
3389void
3390init_ntproc ()
3391{
3392#ifdef HAVE_SOCKETS
f249a012
RS
3393 /* Initialise the socket interface now if available and requested by
3394 the user by defining PRELOAD_WINSOCK; otherwise loading will be
fbd6baed 3395 delayed until open-network-stream is called (w32-has-winsock can
f249a012
RS
3396 also be used to dynamically load or reload winsock).
3397
3398 Conveniently, init_environment is called before us, so
3399 PRELOAD_WINSOCK can be set in the registry. */
3400
3401 /* Always initialize this correctly. */
3402 winsock_lib = NULL;
3403
3404 if (getenv ("PRELOAD_WINSOCK") != NULL)
3405 init_winsock (TRUE);
480b0c5b
GV
3406#endif
3407
3408 /* Initial preparation for subprocess support: replace our standard
3409 handles with non-inheritable versions. */
3410 {
3411 HANDLE parent;
3412 HANDLE stdin_save = INVALID_HANDLE_VALUE;
3413 HANDLE stdout_save = INVALID_HANDLE_VALUE;
3414 HANDLE stderr_save = INVALID_HANDLE_VALUE;
3415
3416 parent = GetCurrentProcess ();
3417
3418 /* ignore errors when duplicating and closing; typically the
3419 handles will be invalid when running as a gui program. */
3420 DuplicateHandle (parent,
3421 GetStdHandle (STD_INPUT_HANDLE),
3422 parent,
3423 &stdin_save,
3424 0,
3425 FALSE,
3426 DUPLICATE_SAME_ACCESS);
3427
3428 DuplicateHandle (parent,
3429 GetStdHandle (STD_OUTPUT_HANDLE),
3430 parent,
3431 &stdout_save,
3432 0,
3433 FALSE,
3434 DUPLICATE_SAME_ACCESS);
3435
3436 DuplicateHandle (parent,
3437 GetStdHandle (STD_ERROR_HANDLE),
3438 parent,
3439 &stderr_save,
3440 0,
3441 FALSE,
3442 DUPLICATE_SAME_ACCESS);
3443
3444 fclose (stdin);
3445 fclose (stdout);
3446 fclose (stderr);
3447
3448 if (stdin_save != INVALID_HANDLE_VALUE)
3449 _open_osfhandle ((long) stdin_save, O_TEXT);
3450 else
76b3903d
GV
3451 _open ("nul", O_TEXT | O_NOINHERIT | O_RDONLY);
3452 _fdopen (0, "r");
480b0c5b
GV
3453
3454 if (stdout_save != INVALID_HANDLE_VALUE)
3455 _open_osfhandle ((long) stdout_save, O_TEXT);
3456 else
76b3903d
GV
3457 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
3458 _fdopen (1, "w");
480b0c5b
GV
3459
3460 if (stderr_save != INVALID_HANDLE_VALUE)
3461 _open_osfhandle ((long) stderr_save, O_TEXT);
3462 else
76b3903d
GV
3463 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
3464 _fdopen (2, "w");
480b0c5b
GV
3465 }
3466
3467 /* unfortunately, atexit depends on implementation of malloc */
3468 /* atexit (term_ntproc); */
3469 signal (SIGABRT, term_ntproc);
76b3903d
GV
3470
3471 /* determine which drives are fixed, for GetCachedVolumeInformation */
3472 {
3473 /* GetDriveType must have trailing backslash. */
3474 char drive[] = "A:\\";
3475
3476 /* Loop over all possible drive letters */
3477 while (*drive <= 'Z')
3478 {
3479 /* Record if this drive letter refers to a fixed drive. */
3480 fixed_drives[DRIVE_INDEX (*drive)] =
3481 (GetDriveType (drive) == DRIVE_FIXED);
3482
3483 (*drive)++;
3484 }
a302c7ae
AI
3485
3486 /* Reset the volume info cache. */
3487 volume_cache = NULL;
76b3903d 3488 }
d54abccd
GV
3489
3490 /* Check to see if Emacs has been installed correctly. */
3491 check_windows_init_file ();
480b0c5b
GV
3492}
3493
3494/* end of nt.c */