Don't set C_OPTIMIZE_SWITCH.
[emacs.git] / src / w32.c
blob67cf9506ad65353c9a4c68c9be5b7ade6756b81d
1 /* Utility and Unix shadow routines for GNU Emacs on the Microsoft W32 API.
2 Copyright (C) 1994, 1995 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
6 GNU Emacs is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.
21 Geoff Voelker (voelker@cs.washington.edu) 7-29-94
25 #include <stddef.h> /* for offsetof */
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <io.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <ctype.h>
32 #include <signal.h>
33 #include <sys/file.h>
34 #include <sys/time.h>
35 #include <sys/utime.h>
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
53 #undef close
54 #undef dup
55 #undef dup2
56 #undef pipe
57 #undef read
58 #undef write
60 #undef strerror
62 #include "lisp.h"
64 #include <pwd.h>
66 #include <windows.h>
68 #ifdef HAVE_SOCKETS /* TCP connection support, if kernel can do it */
69 #include <sys/socket.h>
70 #undef socket
71 #undef bind
72 #undef connect
73 #undef htons
74 #undef ntohs
75 #undef inet_addr
76 #undef gethostname
77 #undef gethostbyname
78 #undef getservbyname
79 #undef shutdown
80 #endif
82 #include "w32.h"
83 #include "ndir.h"
84 #include "w32heap.h"
86 #undef min
87 #undef max
88 #define min(x, y) (((x) < (y)) ? (x) : (y))
89 #define max(x, y) (((x) > (y)) ? (x) : (y))
91 extern Lisp_Object Vw32_downcase_file_names;
92 extern Lisp_Object Vw32_generate_fake_inodes;
93 extern Lisp_Object Vw32_get_true_file_attributes;
94 extern Lisp_Object Vw32_num_mouse_buttons;
96 static char startup_dir[MAXPATHLEN];
98 /* Get the current working directory. */
99 char *
100 getwd (char *dir)
102 #if 0
103 if (GetCurrentDirectory (MAXPATHLEN, dir) > 0)
104 return dir;
105 return NULL;
106 #else
107 /* Emacs doesn't actually change directory itself, and we want to
108 force our real wd to be where emacs.exe is to avoid unnecessary
109 conflicts when trying to rename or delete directories. */
110 strcpy (dir, startup_dir);
111 return dir;
112 #endif
115 #ifndef HAVE_SOCKETS
116 /* Emulate gethostname. */
118 gethostname (char *buffer, int size)
120 /* NT only allows small host names, so the buffer is
121 certainly large enough. */
122 return !GetComputerName (buffer, &size);
124 #endif /* HAVE_SOCKETS */
126 /* Emulate getloadavg. */
128 getloadavg (double loadavg[], int nelem)
130 int i;
132 /* A faithful emulation is going to have to be saved for a rainy day. */
133 for (i = 0; i < nelem; i++)
135 loadavg[i] = 0.0;
137 return i;
140 /* Emulate getpwuid, getpwnam and others. */
142 #define PASSWD_FIELD_SIZE 256
144 static char the_passwd_name[PASSWD_FIELD_SIZE];
145 static char the_passwd_passwd[PASSWD_FIELD_SIZE];
146 static char the_passwd_gecos[PASSWD_FIELD_SIZE];
147 static char the_passwd_dir[PASSWD_FIELD_SIZE];
148 static char the_passwd_shell[PASSWD_FIELD_SIZE];
150 static struct passwd the_passwd =
152 the_passwd_name,
153 the_passwd_passwd,
157 the_passwd_gecos,
158 the_passwd_dir,
159 the_passwd_shell,
162 int
163 getuid ()
165 return the_passwd.pw_uid;
168 int
169 geteuid ()
171 /* I could imagine arguing for checking to see whether the user is
172 in the Administrators group and returning a UID of 0 for that
173 case, but I don't know how wise that would be in the long run. */
174 return getuid ();
177 int
178 getgid ()
180 return the_passwd.pw_gid;
183 int
184 getegid ()
186 return getgid ();
189 struct passwd *
190 getpwuid (int uid)
192 if (uid == the_passwd.pw_uid)
193 return &the_passwd;
194 return NULL;
197 struct passwd *
198 getpwnam (char *name)
200 struct passwd *pw;
202 pw = getpwuid (getuid ());
203 if (!pw)
204 return pw;
206 if (stricmp (name, pw->pw_name))
207 return NULL;
209 return pw;
212 void
213 init_user_info ()
215 /* Find the user's real name by opening the process token and
216 looking up the name associated with the user-sid in that token.
218 Use the relative portion of the identifier authority value from
219 the user-sid as the user id value (same for group id using the
220 primary group sid from the process token). */
222 char user_sid[256], name[256], domain[256];
223 DWORD length = sizeof (name), dlength = sizeof (domain), trash;
224 HANDLE token = NULL;
225 SID_NAME_USE user_type;
227 if (OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY, &token)
228 && GetTokenInformation (token, TokenUser,
229 (PVOID) user_sid, sizeof (user_sid), &trash)
230 && LookupAccountSid (NULL, *((PSID *) user_sid), name, &length,
231 domain, &dlength, &user_type))
233 strcpy (the_passwd.pw_name, name);
234 /* Determine a reasonable uid value. */
235 if (stricmp ("administrator", name) == 0)
237 the_passwd.pw_uid = 0;
238 the_passwd.pw_gid = 0;
240 else
242 SID_IDENTIFIER_AUTHORITY * pSIA;
244 pSIA = GetSidIdentifierAuthority (*((PSID *) user_sid));
245 /* I believe the relative portion is the last 4 bytes (of 6)
246 with msb first. */
247 the_passwd.pw_uid = ((pSIA->Value[2] << 24) +
248 (pSIA->Value[3] << 16) +
249 (pSIA->Value[4] << 8) +
250 (pSIA->Value[5] << 0));
251 /* restrict to conventional uid range for normal users */
252 the_passwd.pw_uid = the_passwd.pw_uid % 60001;
254 /* Get group id */
255 if (GetTokenInformation (token, TokenPrimaryGroup,
256 (PVOID) user_sid, sizeof (user_sid), &trash))
258 SID_IDENTIFIER_AUTHORITY * pSIA;
260 pSIA = GetSidIdentifierAuthority (*((PSID *) user_sid));
261 the_passwd.pw_gid = ((pSIA->Value[2] << 24) +
262 (pSIA->Value[3] << 16) +
263 (pSIA->Value[4] << 8) +
264 (pSIA->Value[5] << 0));
265 /* I don't know if this is necessary, but for safety... */
266 the_passwd.pw_gid = the_passwd.pw_gid % 60001;
268 else
269 the_passwd.pw_gid = the_passwd.pw_uid;
272 /* If security calls are not supported (presumably because we
273 are running under Windows 95), fallback to this. */
274 else if (GetUserName (name, &length))
276 strcpy (the_passwd.pw_name, name);
277 if (stricmp ("administrator", name) == 0)
278 the_passwd.pw_uid = 0;
279 else
280 the_passwd.pw_uid = 123;
281 the_passwd.pw_gid = the_passwd.pw_uid;
283 else
285 strcpy (the_passwd.pw_name, "unknown");
286 the_passwd.pw_uid = 123;
287 the_passwd.pw_gid = 123;
290 /* Ensure HOME and SHELL are defined. */
291 if (getenv ("HOME") == NULL)
292 putenv ("HOME=c:/");
293 if (getenv ("SHELL") == NULL)
294 putenv (os_subtype == OS_WIN95 ? "SHELL=command" : "SHELL=cmd");
296 /* Set dir and shell from environment variables. */
297 strcpy (the_passwd.pw_dir, getenv ("HOME"));
298 strcpy (the_passwd.pw_shell, getenv ("SHELL"));
300 if (token)
301 CloseHandle (token);
305 random ()
307 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
308 return ((rand () << 15) | rand ());
311 void
312 srandom (int seed)
314 srand (seed);
318 /* Normalize filename by converting all path separators to
319 the specified separator. Also conditionally convert upper
320 case path name components to lower case. */
322 static void
323 normalize_filename (fp, path_sep)
324 register char *fp;
325 char path_sep;
327 char sep;
328 char *elem;
330 /* Always lower-case drive letters a-z, even if the filesystem
331 preserves case in filenames.
332 This is so filenames can be compared by string comparison
333 functions that are case-sensitive. Even case-preserving filesystems
334 do not distinguish case in drive letters. */
335 if (fp[1] == ':' && *fp >= 'A' && *fp <= 'Z')
337 *fp += 'a' - 'A';
338 fp += 2;
341 if (NILP (Vw32_downcase_file_names))
343 while (*fp)
345 if (*fp == '/' || *fp == '\\')
346 *fp = path_sep;
347 fp++;
349 return;
352 sep = path_sep; /* convert to this path separator */
353 elem = fp; /* start of current path element */
355 do {
356 if (*fp >= 'a' && *fp <= 'z')
357 elem = 0; /* don't convert this element */
359 if (*fp == 0 || *fp == ':')
361 sep = *fp; /* restore current separator (or 0) */
362 *fp = '/'; /* after conversion of this element */
365 if (*fp == '/' || *fp == '\\')
367 if (elem && elem != fp)
369 *fp = 0; /* temporary end of string */
370 _strlwr (elem); /* while we convert to lower case */
372 *fp = sep; /* convert (or restore) path separator */
373 elem = fp + 1; /* next element starts after separator */
374 sep = path_sep;
376 } while (*fp++);
379 /* Destructively turn backslashes into slashes. */
380 void
381 dostounix_filename (p)
382 register char *p;
384 normalize_filename (p, '/');
387 /* Destructively turn slashes into backslashes. */
388 void
389 unixtodos_filename (p)
390 register char *p;
392 normalize_filename (p, '\\');
395 /* Remove all CR's that are followed by a LF.
396 (From msdos.c...probably should figure out a way to share it,
397 although this code isn't going to ever change.) */
399 crlf_to_lf (n, buf)
400 register int n;
401 register unsigned char *buf;
403 unsigned char *np = buf;
404 unsigned char *startp = buf;
405 unsigned char *endp = buf + n;
407 if (n == 0)
408 return n;
409 while (buf < endp - 1)
411 if (*buf == 0x0d)
413 if (*(++buf) != 0x0a)
414 *np++ = 0x0d;
416 else
417 *np++ = *buf++;
419 if (buf < endp)
420 *np++ = *buf++;
421 return np - startp;
424 /* Parse the root part of file name, if present. Return length and
425 optionally store pointer to char after root. */
426 static int
427 parse_root (char * name, char ** pPath)
429 char * start = name;
431 if (name == NULL)
432 return 0;
434 /* find the root name of the volume if given */
435 if (isalpha (name[0]) && name[1] == ':')
437 /* skip past drive specifier */
438 name += 2;
439 if (IS_DIRECTORY_SEP (name[0]))
440 name++;
442 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
444 int slashes = 2;
445 name += 2;
448 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
449 break;
450 name++;
452 while ( *name );
453 if (IS_DIRECTORY_SEP (name[0]))
454 name++;
457 if (pPath)
458 *pPath = name;
460 return name - start;
463 /* Get long base name for name; name is assumed to be absolute. */
464 static int
465 get_long_basename (char * name, char * buf, int size)
467 WIN32_FIND_DATA find_data;
468 HANDLE dir_handle;
469 int len = 0;
471 /* must be valid filename, no wild cards or other illegal characters */
472 if (strpbrk (name, "*?|<>\""))
473 return 0;
475 dir_handle = FindFirstFile (name, &find_data);
476 if (dir_handle != INVALID_HANDLE_VALUE)
478 if ((len = strlen (find_data.cFileName)) < size)
479 memcpy (buf, find_data.cFileName, len + 1);
480 else
481 len = 0;
482 FindClose (dir_handle);
484 return len;
487 /* Get long name for file, if possible (assumed to be absolute). */
488 BOOL
489 w32_get_long_filename (char * name, char * buf, int size)
491 char * o = buf;
492 char * p;
493 char * q;
494 char full[ MAX_PATH ];
495 int len;
497 len = strlen (name);
498 if (len >= MAX_PATH)
499 return FALSE;
501 /* Use local copy for destructive modification. */
502 memcpy (full, name, len+1);
503 unixtodos_filename (full);
505 /* Copy root part verbatim. */
506 len = parse_root (full, &p);
507 memcpy (o, full, len);
508 o += len;
509 *o = '\0';
510 size -= len;
512 while (p != NULL && *p)
514 q = p;
515 p = strchr (q, '\\');
516 if (p) *p = '\0';
517 len = get_long_basename (full, o, size);
518 if (len > 0)
520 o += len;
521 size -= len;
522 if (p != NULL)
524 *p++ = '\\';
525 if (size < 2)
526 return FALSE;
527 *o++ = '\\';
528 size--;
529 *o = '\0';
532 else
533 return FALSE;
536 return TRUE;
540 is_unc_volume (const char *filename)
542 const char *ptr = filename;
544 if (!IS_DIRECTORY_SEP (ptr[0]) || !IS_DIRECTORY_SEP (ptr[1]) || !ptr[2])
545 return 0;
547 if (strpbrk (ptr + 2, "*?|<>\"\\/"))
548 return 0;
550 return 1;
553 /* Routines that are no-ops on NT but are defined to get Emacs to compile. */
555 int
556 sigsetmask (int signal_mask)
558 return 0;
561 int
562 sigmask (int sig)
564 return 0;
567 int
568 sigblock (int sig)
570 return 0;
573 int
574 sigunblock (int sig)
576 return 0;
579 int
580 setpgrp (int pid, int gid)
582 return 0;
585 int
586 alarm (int seconds)
588 return 0;
591 void
592 unrequest_sigio (void)
594 return;
597 void
598 request_sigio (void)
600 return;
603 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
605 LPBYTE
606 w32_get_resource (key, lpdwtype)
607 char *key;
608 LPDWORD lpdwtype;
610 LPBYTE lpvalue;
611 HKEY hrootkey = NULL;
612 DWORD cbData;
613 BOOL ok = FALSE;
615 /* Check both the current user and the local machine to see if
616 we have any resources. */
618 if (RegOpenKeyEx (HKEY_CURRENT_USER, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
620 lpvalue = NULL;
622 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
623 && (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL
624 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
626 return (lpvalue);
629 if (lpvalue) xfree (lpvalue);
631 RegCloseKey (hrootkey);
634 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
636 lpvalue = NULL;
638 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
639 && (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL
640 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
642 return (lpvalue);
645 if (lpvalue) xfree (lpvalue);
647 RegCloseKey (hrootkey);
650 return (NULL);
653 char *get_emacs_configuration (void);
654 extern Lisp_Object Vsystem_configuration;
656 void
657 init_environment (char ** argv)
659 int len;
660 static const char * const tempdirs[] = {
661 "$TMPDIR", "$TEMP", "$TMP", "c:/"
663 int i;
664 const int imax = sizeof (tempdirs) / sizeof (tempdirs[0]);
666 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
667 temporary files and assume "/tmp" if $TMPDIR is unset, which
668 will break on DOS/Windows. Refuse to work if we cannot find
669 a directory, not even "c:/", usable for that purpose. */
670 for (i = 0; i < imax ; i++)
672 const char *tmp = tempdirs[i];
674 if (*tmp == '$')
675 tmp = getenv (tmp + 1);
676 /* Note that `access' can lie to us if the directory resides on a
677 read-only filesystem, like CD-ROM or a write-protected floppy.
678 The only way to be really sure is to actually create a file and
679 see if it succeeds. But I think that's too much to ask. */
680 if (tmp && access (tmp, D_OK) == 0)
682 char * var = alloca (strlen (tmp) + 8);
683 sprintf (var, "TMPDIR=%s", tmp);
684 putenv (var);
685 break;
688 if (i >= imax)
689 cmd_error_internal
690 (Fcons (Qerror,
691 Fcons (build_string ("no usable temporary directories found!!"),
692 Qnil)),
693 "While setting TMPDIR: ");
695 /* Check for environment variables and use registry if they don't exist */
697 int i;
698 LPBYTE lpval;
699 DWORD dwType;
701 static char * env_vars[] =
703 "HOME",
704 "PRELOAD_WINSOCK",
705 "emacs_dir",
706 "EMACSLOADPATH",
707 "SHELL",
708 "CMDPROXY",
709 "EMACSDATA",
710 "EMACSPATH",
711 "EMACSLOCKDIR",
712 /* We no longer set INFOPATH because Info-default-directory-list
713 is then ignored. We use a hook in winnt.el instead. */
714 /* "INFOPATH", */
715 "EMACSDOC",
716 "TERM",
719 for (i = 0; i < (sizeof (env_vars) / sizeof (env_vars[0])); i++)
721 if (!getenv (env_vars[i])
722 && (lpval = w32_get_resource (env_vars[i], &dwType)) != NULL)
724 if (dwType == REG_EXPAND_SZ)
726 char buf1[500], buf2[500];
728 ExpandEnvironmentStrings ((LPSTR) lpval, buf1, 500);
729 _snprintf (buf2, 499, "%s=%s", env_vars[i], buf1);
730 putenv (strdup (buf2));
732 else if (dwType == REG_SZ)
734 char buf[500];
736 _snprintf (buf, 499, "%s=%s", env_vars[i], lpval);
737 putenv (strdup (buf));
740 xfree (lpval);
745 /* Rebuild system configuration to reflect invoking system. */
746 Vsystem_configuration = build_string (EMACS_CONFIGURATION);
748 /* Another special case: on NT, the PATH variable is actually named
749 "Path" although cmd.exe (perhaps NT itself) arranges for
750 environment variable lookup and setting to be case insensitive.
751 However, Emacs assumes a fully case sensitive environment, so we
752 need to change "Path" to "PATH" to match the expectations of
753 various elisp packages. We do this by the sneaky method of
754 modifying the string in the C runtime environ entry.
756 The same applies to COMSPEC. */
758 char ** envp;
760 for (envp = environ; *envp; envp++)
761 if (_strnicmp (*envp, "PATH=", 5) == 0)
762 memcpy (*envp, "PATH=", 5);
763 else if (_strnicmp (*envp, "COMSPEC=", 8) == 0)
764 memcpy (*envp, "COMSPEC=", 8);
767 /* Remember the initial working directory for getwd, then make the
768 real wd be the location of emacs.exe to avoid conflicts when
769 renaming or deleting directories. (We also don't call chdir when
770 running subprocesses for the same reason.) */
771 if (!GetCurrentDirectory (MAXPATHLEN, startup_dir))
772 abort ();
775 char *p;
776 static char modname[MAX_PATH];
778 if (!GetModuleFileName (NULL, modname, MAX_PATH))
779 abort ();
780 if ((p = strrchr (modname, '\\')) == NULL)
781 abort ();
782 *p = 0;
784 SetCurrentDirectory (modname);
786 /* Ensure argv[0] has the full path to Emacs. */
787 *p = '\\';
788 argv[0] = modname;
791 /* Determine if there is a middle mouse button, to allow parse_button
792 to decide whether right mouse events should be mouse-2 or
793 mouse-3. */
794 XSETINT (Vw32_num_mouse_buttons, GetSystemMetrics (SM_CMOUSEBUTTONS));
796 init_user_info ();
799 /* We don't have scripts to automatically determine the system configuration
800 for Emacs before it's compiled, and we don't want to have to make the
801 user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
802 routine. */
804 static char configuration_buffer[32];
806 char *
807 get_emacs_configuration (void)
809 char *arch, *oem, *os;
810 int build_num;
812 /* Determine the processor type. */
813 switch (get_processor_type ())
816 #ifdef PROCESSOR_INTEL_386
817 case PROCESSOR_INTEL_386:
818 case PROCESSOR_INTEL_486:
819 case PROCESSOR_INTEL_PENTIUM:
820 arch = "i386";
821 break;
822 #endif
824 #ifdef PROCESSOR_INTEL_860
825 case PROCESSOR_INTEL_860:
826 arch = "i860";
827 break;
828 #endif
830 #ifdef PROCESSOR_MIPS_R2000
831 case PROCESSOR_MIPS_R2000:
832 case PROCESSOR_MIPS_R3000:
833 case PROCESSOR_MIPS_R4000:
834 arch = "mips";
835 break;
836 #endif
838 #ifdef PROCESSOR_ALPHA_21064
839 case PROCESSOR_ALPHA_21064:
840 arch = "alpha";
841 break;
842 #endif
844 default:
845 arch = "unknown";
846 break;
849 /* Let oem be "*" until we figure out how to decode the OEM field. */
850 oem = "*";
852 switch (osinfo_cache.dwPlatformId) {
853 case VER_PLATFORM_WIN32_NT:
854 os = "nt";
855 build_num = osinfo_cache.dwBuildNumber;
856 break;
857 case VER_PLATFORM_WIN32_WINDOWS:
858 if (osinfo_cache.dwMinorVersion == 0) {
859 os = "windows95";
860 } else {
861 os = "windows98";
863 build_num = LOWORD (osinfo_cache.dwBuildNumber);
864 break;
865 case VER_PLATFORM_WIN32s:
866 /* Not supported, should not happen. */
867 os = "windows32s";
868 build_num = LOWORD (osinfo_cache.dwBuildNumber);
869 break;
870 default:
871 os = "unknown";
872 build_num = 0;
873 break;
876 if (osinfo_cache.dwPlatformId == VER_PLATFORM_WIN32_NT) {
877 sprintf (configuration_buffer, "%s-%s-%s%d.%d.%d", arch, oem, os,
878 get_w32_major_version (), get_w32_minor_version (), build_num);
879 } else {
880 sprintf (configuration_buffer, "%s-%s-%s.%d", arch, oem, os, build_num);
883 return configuration_buffer;
886 #include <sys/timeb.h>
888 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
889 void
890 gettimeofday (struct timeval *tv, struct timezone *tz)
892 struct _timeb tb;
893 _ftime (&tb);
895 tv->tv_sec = tb.time;
896 tv->tv_usec = tb.millitm * 1000L;
897 if (tz)
899 tz->tz_minuteswest = tb.timezone; /* minutes west of Greenwich */
900 tz->tz_dsttime = tb.dstflag; /* type of dst correction */
904 /* ------------------------------------------------------------------------- */
905 /* IO support and wrapper functions for W32 API. */
906 /* ------------------------------------------------------------------------- */
908 /* Place a wrapper around the MSVC version of ctime. It returns NULL
909 on network directories, so we handle that case here.
910 (Ulrich Leodolter, 1/11/95). */
911 char *
912 sys_ctime (const time_t *t)
914 char *str = (char *) ctime (t);
915 return (str ? str : "Sun Jan 01 00:00:00 1970");
918 /* Emulate sleep...we could have done this with a define, but that
919 would necessitate including windows.h in the files that used it.
920 This is much easier. */
921 void
922 sys_sleep (int seconds)
924 Sleep (seconds * 1000);
927 /* Internal MSVC functions for low-level descriptor munging */
928 extern int __cdecl _set_osfhnd (int fd, long h);
929 extern int __cdecl _free_osfhnd (int fd);
931 /* parallel array of private info on file handles */
932 filedesc fd_info [ MAXDESC ];
934 typedef struct volume_info_data {
935 struct volume_info_data * next;
937 /* time when info was obtained */
938 DWORD timestamp;
940 /* actual volume info */
941 char * root_dir;
942 DWORD serialnum;
943 DWORD maxcomp;
944 DWORD flags;
945 char * name;
946 char * type;
947 } volume_info_data;
949 /* Global referenced by various functions. */
950 static volume_info_data volume_info;
952 /* Vector to indicate which drives are local and fixed (for which cached
953 data never expires). */
954 static BOOL fixed_drives[26];
956 /* Consider cached volume information to be stale if older than 10s,
957 at least for non-local drives. Info for fixed drives is never stale. */
958 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
959 #define VOLINFO_STILL_VALID( root_dir, info ) \
960 ( ( isalpha (root_dir[0]) && \
961 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
962 || GetTickCount () - info->timestamp < 10000 )
964 /* Cache support functions. */
966 /* Simple linked list with linear search is sufficient. */
967 static volume_info_data *volume_cache = NULL;
969 static volume_info_data *
970 lookup_volume_info (char * root_dir)
972 volume_info_data * info;
974 for (info = volume_cache; info; info = info->next)
975 if (stricmp (info->root_dir, root_dir) == 0)
976 break;
977 return info;
980 static void
981 add_volume_info (char * root_dir, volume_info_data * info)
983 info->root_dir = strdup (root_dir);
984 info->next = volume_cache;
985 volume_cache = info;
989 /* Wrapper for GetVolumeInformation, which uses caching to avoid
990 performance penalty (~2ms on 486 for local drives, 7.5ms for local
991 cdrom drive, ~5-10ms or more for remote drives on LAN). */
992 volume_info_data *
993 GetCachedVolumeInformation (char * root_dir)
995 volume_info_data * info;
996 char default_root[ MAX_PATH ];
998 /* NULL for root_dir means use root from current directory. */
999 if (root_dir == NULL)
1001 if (GetCurrentDirectory (MAX_PATH, default_root) == 0)
1002 return NULL;
1003 parse_root (default_root, &root_dir);
1004 *root_dir = 0;
1005 root_dir = default_root;
1008 /* Local fixed drives can be cached permanently. Removable drives
1009 cannot be cached permanently, since the volume name and serial
1010 number (if nothing else) can change. Remote drives should be
1011 treated as if they are removable, since there is no sure way to
1012 tell whether they are or not. Also, the UNC association of drive
1013 letters mapped to remote volumes can be changed at any time (even
1014 by other processes) without notice.
1016 As a compromise, so we can benefit from caching info for remote
1017 volumes, we use a simple expiry mechanism to invalidate cache
1018 entries that are more than ten seconds old. */
1020 #if 0
1021 /* No point doing this, because WNetGetConnection is even slower than
1022 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
1023 GetDriveType is about the only call of this type which does not
1024 involve network access, and so is extremely quick). */
1026 /* Map drive letter to UNC if remote. */
1027 if ( isalpha( root_dir[0] ) && !fixed[ DRIVE_INDEX( root_dir[0] ) ] )
1029 char remote_name[ 256 ];
1030 char drive[3] = { root_dir[0], ':' };
1032 if (WNetGetConnection (drive, remote_name, sizeof (remote_name))
1033 == NO_ERROR)
1034 /* do something */ ;
1036 #endif
1038 info = lookup_volume_info (root_dir);
1040 if (info == NULL || ! VOLINFO_STILL_VALID (root_dir, info))
1042 char name[ 256 ];
1043 DWORD serialnum;
1044 DWORD maxcomp;
1045 DWORD flags;
1046 char type[ 256 ];
1048 /* Info is not cached, or is stale. */
1049 if (!GetVolumeInformation (root_dir,
1050 name, sizeof (name),
1051 &serialnum,
1052 &maxcomp,
1053 &flags,
1054 type, sizeof (type)))
1055 return NULL;
1057 /* Cache the volume information for future use, overwriting existing
1058 entry if present. */
1059 if (info == NULL)
1061 info = (volume_info_data *) xmalloc (sizeof (volume_info_data));
1062 add_volume_info (root_dir, info);
1064 else
1066 free (info->name);
1067 free (info->type);
1070 info->name = strdup (name);
1071 info->serialnum = serialnum;
1072 info->maxcomp = maxcomp;
1073 info->flags = flags;
1074 info->type = strdup (type);
1075 info->timestamp = GetTickCount ();
1078 return info;
1081 /* Get information on the volume where name is held; set path pointer to
1082 start of pathname in name (past UNC header\volume header if present). */
1084 get_volume_info (const char * name, const char ** pPath)
1086 char temp[MAX_PATH];
1087 char *rootname = NULL; /* default to current volume */
1088 volume_info_data * info;
1090 if (name == NULL)
1091 return FALSE;
1093 /* find the root name of the volume if given */
1094 if (isalpha (name[0]) && name[1] == ':')
1096 rootname = temp;
1097 temp[0] = *name++;
1098 temp[1] = *name++;
1099 temp[2] = '\\';
1100 temp[3] = 0;
1102 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
1104 char *str = temp;
1105 int slashes = 4;
1106 rootname = temp;
1109 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
1110 break;
1111 *str++ = *name++;
1113 while ( *name );
1115 *str++ = '\\';
1116 *str = 0;
1119 if (pPath)
1120 *pPath = name;
1122 info = GetCachedVolumeInformation (rootname);
1123 if (info != NULL)
1125 /* Set global referenced by other functions. */
1126 volume_info = *info;
1127 return TRUE;
1129 return FALSE;
1132 /* Determine if volume is FAT format (ie. only supports short 8.3
1133 names); also set path pointer to start of pathname in name. */
1135 is_fat_volume (const char * name, const char ** pPath)
1137 if (get_volume_info (name, pPath))
1138 return (volume_info.maxcomp == 12);
1139 return FALSE;
1142 /* Map filename to a legal 8.3 name if necessary. */
1143 const char *
1144 map_w32_filename (const char * name, const char ** pPath)
1146 static char shortname[MAX_PATH];
1147 char * str = shortname;
1148 char c;
1149 char * path;
1150 const char * save_name = name;
1152 if (is_fat_volume (name, &path)) /* truncate to 8.3 */
1154 register int left = 8; /* maximum number of chars in part */
1155 register int extn = 0; /* extension added? */
1156 register int dots = 2; /* maximum number of dots allowed */
1158 while (name < path)
1159 *str++ = *name++; /* skip past UNC header */
1161 while ((c = *name++))
1163 switch ( c )
1165 case '\\':
1166 case '/':
1167 *str++ = '\\';
1168 extn = 0; /* reset extension flags */
1169 dots = 2; /* max 2 dots */
1170 left = 8; /* max length 8 for main part */
1171 break;
1172 case ':':
1173 *str++ = ':';
1174 extn = 0; /* reset extension flags */
1175 dots = 2; /* max 2 dots */
1176 left = 8; /* max length 8 for main part */
1177 break;
1178 case '.':
1179 if ( dots )
1181 /* Convert path components of the form .xxx to _xxx,
1182 but leave . and .. as they are. This allows .emacs
1183 to be read as _emacs, for example. */
1185 if (! *name ||
1186 *name == '.' ||
1187 IS_DIRECTORY_SEP (*name))
1189 *str++ = '.';
1190 dots--;
1192 else
1194 *str++ = '_';
1195 left--;
1196 dots = 0;
1199 else if ( !extn )
1201 *str++ = '.';
1202 extn = 1; /* we've got an extension */
1203 left = 3; /* 3 chars in extension */
1205 else
1207 /* any embedded dots after the first are converted to _ */
1208 *str++ = '_';
1210 break;
1211 case '~':
1212 case '#': /* don't lose these, they're important */
1213 if ( ! left )
1214 str[-1] = c; /* replace last character of part */
1215 /* FALLTHRU */
1216 default:
1217 if ( left )
1219 *str++ = tolower (c); /* map to lower case (looks nicer) */
1220 left--;
1221 dots = 0; /* started a path component */
1223 break;
1226 *str = '\0';
1228 else
1230 strcpy (shortname, name);
1231 unixtodos_filename (shortname);
1234 if (pPath)
1235 *pPath = shortname + (path - save_name);
1237 return shortname;
1240 static int
1241 is_exec (const char * name)
1243 char * p = strrchr (name, '.');
1244 return
1245 (p != NULL
1246 && (stricmp (p, ".exe") == 0 ||
1247 stricmp (p, ".com") == 0 ||
1248 stricmp (p, ".bat") == 0 ||
1249 stricmp (p, ".cmd") == 0));
1252 /* Emulate the Unix directory procedures opendir, closedir,
1253 and readdir. We can't use the procedures supplied in sysdep.c,
1254 so we provide them here. */
1256 struct direct dir_static; /* simulated directory contents */
1257 static HANDLE dir_find_handle = INVALID_HANDLE_VALUE;
1258 static int dir_is_fat;
1259 static char dir_pathname[MAXPATHLEN+1];
1260 static WIN32_FIND_DATA dir_find_data;
1262 /* Support shares on a network resource as subdirectories of a read-only
1263 root directory. */
1264 static HANDLE wnet_enum_handle = INVALID_HANDLE_VALUE;
1265 HANDLE open_unc_volume (char *);
1266 char *read_unc_volume (HANDLE, char *, int);
1267 void close_unc_volume (HANDLE);
1269 DIR *
1270 opendir (char *filename)
1272 DIR *dirp;
1274 /* Opening is done by FindFirstFile. However, a read is inherent to
1275 this operation, so we defer the open until read time. */
1277 if (dir_find_handle != INVALID_HANDLE_VALUE)
1278 return NULL;
1279 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
1280 return NULL;
1282 if (is_unc_volume (filename))
1284 wnet_enum_handle = open_unc_volume (filename);
1285 if (wnet_enum_handle == INVALID_HANDLE_VALUE)
1286 return NULL;
1289 if (!(dirp = (DIR *) malloc (sizeof (DIR))))
1290 return NULL;
1292 dirp->dd_fd = 0;
1293 dirp->dd_loc = 0;
1294 dirp->dd_size = 0;
1296 strncpy (dir_pathname, map_w32_filename (filename, NULL), MAXPATHLEN);
1297 dir_pathname[MAXPATHLEN] = '\0';
1298 dir_is_fat = is_fat_volume (filename, NULL);
1300 return dirp;
1303 void
1304 closedir (DIR *dirp)
1306 /* If we have a find-handle open, close it. */
1307 if (dir_find_handle != INVALID_HANDLE_VALUE)
1309 FindClose (dir_find_handle);
1310 dir_find_handle = INVALID_HANDLE_VALUE;
1312 else if (wnet_enum_handle != INVALID_HANDLE_VALUE)
1314 close_unc_volume (wnet_enum_handle);
1315 wnet_enum_handle = INVALID_HANDLE_VALUE;
1317 xfree ((char *) dirp);
1320 struct direct *
1321 readdir (DIR *dirp)
1323 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
1325 if (!read_unc_volume (wnet_enum_handle,
1326 dir_find_data.cFileName,
1327 MAX_PATH))
1328 return NULL;
1330 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
1331 else if (dir_find_handle == INVALID_HANDLE_VALUE)
1333 char filename[MAXNAMLEN + 3];
1334 int ln;
1336 strcpy (filename, dir_pathname);
1337 ln = strlen (filename) - 1;
1338 if (!IS_DIRECTORY_SEP (filename[ln]))
1339 strcat (filename, "\\");
1340 strcat (filename, "*");
1342 dir_find_handle = FindFirstFile (filename, &dir_find_data);
1344 if (dir_find_handle == INVALID_HANDLE_VALUE)
1345 return NULL;
1347 else
1349 if (!FindNextFile (dir_find_handle, &dir_find_data))
1350 return NULL;
1353 /* Emacs never uses this value, so don't bother making it match
1354 value returned by stat(). */
1355 dir_static.d_ino = 1;
1357 dir_static.d_reclen = sizeof (struct direct) - MAXNAMLEN + 3 +
1358 dir_static.d_namlen - dir_static.d_namlen % 4;
1360 dir_static.d_namlen = strlen (dir_find_data.cFileName);
1361 strcpy (dir_static.d_name, dir_find_data.cFileName);
1362 if (dir_is_fat)
1363 _strlwr (dir_static.d_name);
1364 else if (!NILP (Vw32_downcase_file_names))
1366 register char *p;
1367 for (p = dir_static.d_name; *p; p++)
1368 if (*p >= 'a' && *p <= 'z')
1369 break;
1370 if (!*p)
1371 _strlwr (dir_static.d_name);
1374 return &dir_static;
1377 HANDLE
1378 open_unc_volume (char *path)
1380 NETRESOURCE nr;
1381 HANDLE henum;
1382 int result;
1384 nr.dwScope = RESOURCE_GLOBALNET;
1385 nr.dwType = RESOURCETYPE_DISK;
1386 nr.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
1387 nr.dwUsage = RESOURCEUSAGE_CONTAINER;
1388 nr.lpLocalName = NULL;
1389 nr.lpRemoteName = map_w32_filename (path, NULL);
1390 nr.lpComment = NULL;
1391 nr.lpProvider = NULL;
1393 result = WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
1394 RESOURCEUSAGE_CONNECTABLE, &nr, &henum);
1396 if (result == NO_ERROR)
1397 return henum;
1398 else
1399 return INVALID_HANDLE_VALUE;
1402 char *
1403 read_unc_volume (HANDLE henum, char *readbuf, int size)
1405 int count;
1406 int result;
1407 int bufsize = 512;
1408 char *buffer;
1409 char *ptr;
1411 count = 1;
1412 buffer = alloca (bufsize);
1413 result = WNetEnumResource (wnet_enum_handle, &count, buffer, &bufsize);
1414 if (result != NO_ERROR)
1415 return NULL;
1417 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
1418 ptr = ((LPNETRESOURCE) buffer)->lpRemoteName;
1419 ptr += 2;
1420 while (*ptr && !IS_DIRECTORY_SEP (*ptr)) ptr++;
1421 ptr++;
1423 strncpy (readbuf, ptr, size);
1424 return readbuf;
1427 void
1428 close_unc_volume (HANDLE henum)
1430 if (henum != INVALID_HANDLE_VALUE)
1431 WNetCloseEnum (henum);
1434 DWORD
1435 unc_volume_file_attributes (char *path)
1437 HANDLE henum;
1438 DWORD attrs;
1440 henum = open_unc_volume (path);
1441 if (henum == INVALID_HANDLE_VALUE)
1442 return -1;
1444 attrs = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY;
1446 close_unc_volume (henum);
1448 return attrs;
1452 /* Shadow some MSVC runtime functions to map requests for long filenames
1453 to reasonable short names if necessary. This was originally added to
1454 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
1455 long file names. */
1458 sys_access (const char * path, int mode)
1460 DWORD attributes;
1462 /* MSVC implementation doesn't recognize D_OK. */
1463 path = map_w32_filename (path, NULL);
1464 if (is_unc_volume (path))
1466 attributes = unc_volume_file_attributes (path);
1467 if (attributes == -1) {
1468 errno = EACCES;
1469 return -1;
1472 else if ((attributes = GetFileAttributes (path)) == -1)
1474 /* Should try mapping GetLastError to errno; for now just indicate
1475 that path doesn't exist. */
1476 errno = EACCES;
1477 return -1;
1479 if ((mode & X_OK) != 0 && !is_exec (path))
1481 errno = EACCES;
1482 return -1;
1484 if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0)
1486 errno = EACCES;
1487 return -1;
1489 if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
1491 errno = EACCES;
1492 return -1;
1494 return 0;
1498 sys_chdir (const char * path)
1500 return _chdir (map_w32_filename (path, NULL));
1504 sys_chmod (const char * path, int mode)
1506 return _chmod (map_w32_filename (path, NULL), mode);
1510 sys_creat (const char * path, int mode)
1512 return _creat (map_w32_filename (path, NULL), mode);
1515 FILE *
1516 sys_fopen(const char * path, const char * mode)
1518 int fd;
1519 int oflag;
1520 const char * mode_save = mode;
1522 /* Force all file handles to be non-inheritable. This is necessary to
1523 ensure child processes don't unwittingly inherit handles that might
1524 prevent future file access. */
1526 if (mode[0] == 'r')
1527 oflag = O_RDONLY;
1528 else if (mode[0] == 'w' || mode[0] == 'a')
1529 oflag = O_WRONLY | O_CREAT | O_TRUNC;
1530 else
1531 return NULL;
1533 /* Only do simplistic option parsing. */
1534 while (*++mode)
1535 if (mode[0] == '+')
1537 oflag &= ~(O_RDONLY | O_WRONLY);
1538 oflag |= O_RDWR;
1540 else if (mode[0] == 'b')
1542 oflag &= ~O_TEXT;
1543 oflag |= O_BINARY;
1545 else if (mode[0] == 't')
1547 oflag &= ~O_BINARY;
1548 oflag |= O_TEXT;
1550 else break;
1552 fd = _open (map_w32_filename (path, NULL), oflag | _O_NOINHERIT, 0644);
1553 if (fd < 0)
1554 return NULL;
1556 return _fdopen (fd, mode_save);
1559 /* This only works on NTFS volumes, but is useful to have. */
1561 sys_link (const char * old, const char * new)
1563 HANDLE fileh;
1564 int result = -1;
1565 char oldname[MAX_PATH], newname[MAX_PATH];
1567 if (old == NULL || new == NULL)
1569 errno = ENOENT;
1570 return -1;
1573 strcpy (oldname, map_w32_filename (old, NULL));
1574 strcpy (newname, map_w32_filename (new, NULL));
1576 fileh = CreateFile (oldname, 0, 0, NULL, OPEN_EXISTING,
1577 FILE_FLAG_BACKUP_SEMANTICS, NULL);
1578 if (fileh != INVALID_HANDLE_VALUE)
1580 int wlen;
1582 /* Confusingly, the "alternate" stream name field does not apply
1583 when restoring a hard link, and instead contains the actual
1584 stream data for the link (ie. the name of the link to create).
1585 The WIN32_STREAM_ID structure before the cStreamName field is
1586 the stream header, which is then immediately followed by the
1587 stream data. */
1589 struct {
1590 WIN32_STREAM_ID wid;
1591 WCHAR wbuffer[MAX_PATH]; /* extra space for link name */
1592 } data;
1594 wlen = MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, newname, -1,
1595 data.wid.cStreamName, MAX_PATH);
1596 if (wlen > 0)
1598 LPVOID context = NULL;
1599 DWORD wbytes = 0;
1601 data.wid.dwStreamId = BACKUP_LINK;
1602 data.wid.dwStreamAttributes = 0;
1603 data.wid.Size.LowPart = wlen * sizeof(WCHAR);
1604 data.wid.Size.HighPart = 0;
1605 data.wid.dwStreamNameSize = 0;
1607 if (BackupWrite (fileh, (LPBYTE)&data,
1608 offsetof (WIN32_STREAM_ID, cStreamName)
1609 + data.wid.Size.LowPart,
1610 &wbytes, FALSE, FALSE, &context)
1611 && BackupWrite (fileh, NULL, 0, &wbytes, TRUE, FALSE, &context))
1613 /* succeeded */
1614 result = 0;
1616 else
1618 /* Should try mapping GetLastError to errno; for now just
1619 indicate a general error (eg. links not supported). */
1620 errno = EINVAL; // perhaps EMLINK?
1624 CloseHandle (fileh);
1626 else
1627 errno = ENOENT;
1629 return result;
1633 sys_mkdir (const char * path)
1635 return _mkdir (map_w32_filename (path, NULL));
1638 /* Because of long name mapping issues, we need to implement this
1639 ourselves. Also, MSVC's _mktemp returns NULL when it can't generate
1640 a unique name, instead of setting the input template to an empty
1641 string.
1643 Standard algorithm seems to be use pid or tid with a letter on the
1644 front (in place of the 6 X's) and cycle through the letters to find a
1645 unique name. We extend that to allow any reasonable character as the
1646 first of the 6 X's. */
1647 char *
1648 sys_mktemp (char * template)
1650 char * p;
1651 int i;
1652 unsigned uid = GetCurrentThreadId ();
1653 static char first_char[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
1655 if (template == NULL)
1656 return NULL;
1657 p = template + strlen (template);
1658 i = 5;
1659 /* replace up to the last 5 X's with uid in decimal */
1660 while (--p >= template && p[0] == 'X' && --i >= 0)
1662 p[0] = '0' + uid % 10;
1663 uid /= 10;
1666 if (i < 0 && p[0] == 'X')
1668 i = 0;
1671 int save_errno = errno;
1672 p[0] = first_char[i];
1673 if (sys_access (template, 0) < 0)
1675 errno = save_errno;
1676 return template;
1679 while (++i < sizeof (first_char));
1682 /* Template is badly formed or else we can't generate a unique name,
1683 so return empty string */
1684 template[0] = 0;
1685 return template;
1689 sys_open (const char * path, int oflag, int mode)
1691 /* Force all file handles to be non-inheritable. */
1692 return _open (map_w32_filename (path, NULL), oflag | _O_NOINHERIT, mode);
1696 sys_rename (const char * oldname, const char * newname)
1698 int result;
1699 char temp[MAX_PATH];
1701 /* MoveFile on Windows 95 doesn't correctly change the short file name
1702 alias in a number of circumstances (it is not easy to predict when
1703 just by looking at oldname and newname, unfortunately). In these
1704 cases, renaming through a temporary name avoids the problem.
1706 A second problem on Windows 95 is that renaming through a temp name when
1707 newname is uppercase fails (the final long name ends up in
1708 lowercase, although the short alias might be uppercase) UNLESS the
1709 long temp name is not 8.3.
1711 So, on Windows 95 we always rename through a temp name, and we make sure
1712 the temp name has a long extension to ensure correct renaming. */
1714 strcpy (temp, map_w32_filename (oldname, NULL));
1716 if (os_subtype == OS_WIN95)
1718 char * o;
1719 char * p;
1720 int i = 0;
1722 oldname = map_w32_filename (oldname, NULL);
1723 if (o = strrchr (oldname, '\\'))
1724 o++;
1725 else
1726 o = (char *) oldname;
1728 if (p = strrchr (temp, '\\'))
1729 p++;
1730 else
1731 p = temp;
1735 /* Force temp name to require a manufactured 8.3 alias - this
1736 seems to make the second rename work properly. */
1737 sprintf (p, "_.%s.%u", o, i);
1738 i++;
1739 result = rename (oldname, temp);
1741 /* This loop must surely terminate! */
1742 while (result < 0 && (errno == EEXIST || errno == EACCES));
1743 if (result < 0)
1744 return -1;
1747 /* Emulate Unix behaviour - newname is deleted if it already exists
1748 (at least if it is a file; don't do this for directories).
1750 Since we mustn't do this if we are just changing the case of the
1751 file name (we would end up deleting the file we are trying to
1752 rename!), we let rename detect if the destination file already
1753 exists - that way we avoid the possible pitfalls of trying to
1754 determine ourselves whether two names really refer to the same
1755 file, which is not always possible in the general case. (Consider
1756 all the permutations of shared or subst'd drives, etc.) */
1758 newname = map_w32_filename (newname, NULL);
1759 result = rename (temp, newname);
1761 if (result < 0
1762 && (errno == EEXIST || errno == EACCES)
1763 && _chmod (newname, 0666) == 0
1764 && _unlink (newname) == 0)
1765 result = rename (temp, newname);
1767 return result;
1771 sys_rmdir (const char * path)
1773 return _rmdir (map_w32_filename (path, NULL));
1777 sys_unlink (const char * path)
1779 path = map_w32_filename (path, NULL);
1781 /* On Unix, unlink works without write permission. */
1782 _chmod (path, 0666);
1783 return _unlink (path);
1786 static FILETIME utc_base_ft;
1787 static long double utc_base;
1788 static int init = 0;
1790 static time_t
1791 convert_time (FILETIME ft)
1793 long double ret;
1795 if (!init)
1797 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
1798 SYSTEMTIME st;
1800 st.wYear = 1970;
1801 st.wMonth = 1;
1802 st.wDay = 1;
1803 st.wHour = 0;
1804 st.wMinute = 0;
1805 st.wSecond = 0;
1806 st.wMilliseconds = 0;
1808 SystemTimeToFileTime (&st, &utc_base_ft);
1809 utc_base = (long double) utc_base_ft.dwHighDateTime
1810 * 4096 * 1024 * 1024 + utc_base_ft.dwLowDateTime;
1811 init = 1;
1814 if (CompareFileTime (&ft, &utc_base_ft) < 0)
1815 return 0;
1817 ret = (long double) ft.dwHighDateTime * 4096 * 1024 * 1024 + ft.dwLowDateTime;
1818 ret -= utc_base;
1819 return (time_t) (ret * 1e-7);
1822 void
1823 convert_from_time_t (time_t time, FILETIME * pft)
1825 long double tmp;
1827 if (!init)
1829 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
1830 SYSTEMTIME st;
1832 st.wYear = 1970;
1833 st.wMonth = 1;
1834 st.wDay = 1;
1835 st.wHour = 0;
1836 st.wMinute = 0;
1837 st.wSecond = 0;
1838 st.wMilliseconds = 0;
1840 SystemTimeToFileTime (&st, &utc_base_ft);
1841 utc_base = (long double) utc_base_ft.dwHighDateTime
1842 * 4096 * 1024 * 1024 + utc_base_ft.dwLowDateTime;
1843 init = 1;
1846 /* time in 100ns units since 1-Jan-1601 */
1847 tmp = (long double) time * 1e7 + utc_base;
1848 pft->dwHighDateTime = (DWORD) (tmp / (4096.0 * 1024 * 1024));
1849 pft->dwLowDateTime = (DWORD) (tmp - (4096.0 * 1024 * 1024) * pft->dwHighDateTime);
1852 #if 0
1853 /* No reason to keep this; faking inode values either by hashing or even
1854 using the file index from GetInformationByHandle, is not perfect and
1855 so by default Emacs doesn't use the inode values on Windows.
1856 Instead, we now determine file-truename correctly (except for
1857 possible drive aliasing etc). */
1859 /* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
1860 static unsigned
1861 hashval (const unsigned char * str)
1863 unsigned h = 0;
1864 while (*str)
1866 h = (h << 4) + *str++;
1867 h ^= (h >> 28);
1869 return h;
1872 /* Return the hash value of the canonical pathname, excluding the
1873 drive/UNC header, to get a hopefully unique inode number. */
1874 static DWORD
1875 generate_inode_val (const char * name)
1877 char fullname[ MAX_PATH ];
1878 char * p;
1879 unsigned hash;
1881 /* Get the truly canonical filename, if it exists. (Note: this
1882 doesn't resolve aliasing due to subst commands, or recognise hard
1883 links. */
1884 if (!w32_get_long_filename ((char *)name, fullname, MAX_PATH))
1885 abort ();
1887 parse_root (fullname, &p);
1888 /* Normal W32 filesystems are still case insensitive. */
1889 _strlwr (p);
1890 return hashval (p);
1893 #endif
1895 /* MSVC stat function can't cope with UNC names and has other bugs, so
1896 replace it with our own. This also allows us to calculate consistent
1897 inode values without hacks in the main Emacs code. */
1899 stat (const char * path, struct stat * buf)
1901 char *name, *r;
1902 WIN32_FIND_DATA wfd;
1903 HANDLE fh;
1904 DWORD fake_inode;
1905 int permission;
1906 int len;
1907 int rootdir = FALSE;
1909 if (path == NULL || buf == NULL)
1911 errno = EFAULT;
1912 return -1;
1915 name = (char *) map_w32_filename (path, &path);
1916 /* must be valid filename, no wild cards or other illegal characters */
1917 if (strpbrk (name, "*?|<>\""))
1919 errno = ENOENT;
1920 return -1;
1923 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
1924 r = IS_DEVICE_SEP (name[1]) ? &name[2] : name;
1925 if (IS_DIRECTORY_SEP (r[0]) && r[1] == '.' && r[2] == '.' && r[3] == '\0')
1927 r[1] = r[2] = '\0';
1930 /* Remove trailing directory separator, unless name is the root
1931 directory of a drive or UNC volume in which case ensure there
1932 is a trailing separator. */
1933 len = strlen (name);
1934 rootdir = (path >= name + len - 1
1935 && (IS_DIRECTORY_SEP (*path) || *path == 0));
1936 name = strcpy (alloca (len + 2), name);
1938 if (is_unc_volume (name))
1940 DWORD attrs = unc_volume_file_attributes (name);
1942 if (attrs == -1)
1943 return -1;
1945 memset (&wfd, 0, sizeof (wfd));
1946 wfd.dwFileAttributes = attrs;
1947 wfd.ftCreationTime = utc_base_ft;
1948 wfd.ftLastAccessTime = utc_base_ft;
1949 wfd.ftLastWriteTime = utc_base_ft;
1950 strcpy (wfd.cFileName, name);
1952 else if (rootdir)
1954 if (!IS_DIRECTORY_SEP (name[len-1]))
1955 strcat (name, "\\");
1956 if (GetDriveType (name) < 2)
1958 errno = ENOENT;
1959 return -1;
1961 memset (&wfd, 0, sizeof (wfd));
1962 wfd.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
1963 wfd.ftCreationTime = utc_base_ft;
1964 wfd.ftLastAccessTime = utc_base_ft;
1965 wfd.ftLastWriteTime = utc_base_ft;
1966 strcpy (wfd.cFileName, name);
1968 else
1970 if (IS_DIRECTORY_SEP (name[len-1]))
1971 name[len - 1] = 0;
1973 /* (This is hacky, but helps when doing file completions on
1974 network drives.) Optimize by using information available from
1975 active readdir if possible. */
1976 len = strlen (dir_pathname);
1977 if (IS_DIRECTORY_SEP (dir_pathname[len-1]))
1978 len--;
1979 if (dir_find_handle != INVALID_HANDLE_VALUE
1980 && strnicmp (name, dir_pathname, len) == 0
1981 && IS_DIRECTORY_SEP (name[len])
1982 && stricmp (name + len + 1, dir_static.d_name) == 0)
1984 /* This was the last entry returned by readdir. */
1985 wfd = dir_find_data;
1987 else
1989 fh = FindFirstFile (name, &wfd);
1990 if (fh == INVALID_HANDLE_VALUE)
1992 errno = ENOENT;
1993 return -1;
1995 FindClose (fh);
1999 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
2001 buf->st_mode = _S_IFDIR;
2002 buf->st_nlink = 2; /* doesn't really matter */
2003 fake_inode = 0; /* this doesn't either I think */
2005 else if (!NILP (Vw32_get_true_file_attributes)
2006 /* No access rights required to get info. */
2007 && (fh = CreateFile (name, 0, 0, NULL, OPEN_EXISTING, 0, NULL))
2008 != INVALID_HANDLE_VALUE)
2010 /* This is more accurate in terms of gettting the correct number
2011 of links, but is quite slow (it is noticable when Emacs is
2012 making a list of file name completions). */
2013 BY_HANDLE_FILE_INFORMATION info;
2015 if (GetFileInformationByHandle (fh, &info))
2017 buf->st_nlink = info.nNumberOfLinks;
2018 /* Might as well use file index to fake inode values, but this
2019 is not guaranteed to be unique unless we keep a handle open
2020 all the time (even then there are situations where it is
2021 not unique). Reputedly, there are at most 48 bits of info
2022 (on NTFS, presumably less on FAT). */
2023 fake_inode = info.nFileIndexLow ^ info.nFileIndexHigh;
2025 else
2027 buf->st_nlink = 1;
2028 fake_inode = 0;
2031 switch (GetFileType (fh))
2033 case FILE_TYPE_DISK:
2034 buf->st_mode = _S_IFREG;
2035 break;
2036 case FILE_TYPE_PIPE:
2037 buf->st_mode = _S_IFIFO;
2038 break;
2039 case FILE_TYPE_CHAR:
2040 case FILE_TYPE_UNKNOWN:
2041 default:
2042 buf->st_mode = _S_IFCHR;
2044 CloseHandle (fh);
2046 else
2048 /* Don't bother to make this information more accurate. */
2049 buf->st_mode = _S_IFREG;
2050 buf->st_nlink = 1;
2051 fake_inode = 0;
2054 #if 0
2055 /* Not sure if there is any point in this. */
2056 if (!NILP (Vw32_generate_fake_inodes))
2057 fake_inode = generate_inode_val (name);
2058 else if (fake_inode == 0)
2060 /* For want of something better, try to make everything unique. */
2061 static DWORD gen_num = 0;
2062 fake_inode = ++gen_num;
2064 #endif
2066 /* MSVC defines _ino_t to be short; other libc's might not. */
2067 if (sizeof (buf->st_ino) == 2)
2068 buf->st_ino = fake_inode ^ (fake_inode >> 16);
2069 else
2070 buf->st_ino = fake_inode;
2072 /* consider files to belong to current user */
2073 buf->st_uid = the_passwd.pw_uid;
2074 buf->st_gid = the_passwd.pw_gid;
2076 /* volume_info is set indirectly by map_w32_filename */
2077 buf->st_dev = volume_info.serialnum;
2078 buf->st_rdev = volume_info.serialnum;
2081 buf->st_size = wfd.nFileSizeLow;
2083 /* Convert timestamps to Unix format. */
2084 buf->st_mtime = convert_time (wfd.ftLastWriteTime);
2085 buf->st_atime = convert_time (wfd.ftLastAccessTime);
2086 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
2087 buf->st_ctime = convert_time (wfd.ftCreationTime);
2088 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
2090 /* determine rwx permissions */
2091 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
2092 permission = _S_IREAD;
2093 else
2094 permission = _S_IREAD | _S_IWRITE;
2096 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
2097 permission |= _S_IEXEC;
2098 else if (is_exec (name))
2099 permission |= _S_IEXEC;
2101 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
2103 return 0;
2106 /* Provide fstat and utime as well as stat for consistent handling of
2107 file timestamps. */
2109 fstat (int desc, struct stat * buf)
2111 HANDLE fh = (HANDLE) _get_osfhandle (desc);
2112 BY_HANDLE_FILE_INFORMATION info;
2113 DWORD fake_inode;
2114 int permission;
2116 switch (GetFileType (fh) & ~FILE_TYPE_REMOTE)
2118 case FILE_TYPE_DISK:
2119 buf->st_mode = _S_IFREG;
2120 if (!GetFileInformationByHandle (fh, &info))
2122 errno = EACCES;
2123 return -1;
2125 break;
2126 case FILE_TYPE_PIPE:
2127 buf->st_mode = _S_IFIFO;
2128 goto non_disk;
2129 case FILE_TYPE_CHAR:
2130 case FILE_TYPE_UNKNOWN:
2131 default:
2132 buf->st_mode = _S_IFCHR;
2133 non_disk:
2134 memset (&info, 0, sizeof (info));
2135 info.dwFileAttributes = 0;
2136 info.ftCreationTime = utc_base_ft;
2137 info.ftLastAccessTime = utc_base_ft;
2138 info.ftLastWriteTime = utc_base_ft;
2141 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
2143 buf->st_mode = _S_IFDIR;
2144 buf->st_nlink = 2; /* doesn't really matter */
2145 fake_inode = 0; /* this doesn't either I think */
2147 else
2149 buf->st_nlink = info.nNumberOfLinks;
2150 /* Might as well use file index to fake inode values, but this
2151 is not guaranteed to be unique unless we keep a handle open
2152 all the time (even then there are situations where it is
2153 not unique). Reputedly, there are at most 48 bits of info
2154 (on NTFS, presumably less on FAT). */
2155 fake_inode = info.nFileIndexLow ^ info.nFileIndexHigh;
2158 /* MSVC defines _ino_t to be short; other libc's might not. */
2159 if (sizeof (buf->st_ino) == 2)
2160 buf->st_ino = fake_inode ^ (fake_inode >> 16);
2161 else
2162 buf->st_ino = fake_inode;
2164 /* consider files to belong to current user */
2165 buf->st_uid = 0;
2166 buf->st_gid = 0;
2168 buf->st_dev = info.dwVolumeSerialNumber;
2169 buf->st_rdev = info.dwVolumeSerialNumber;
2171 buf->st_size = info.nFileSizeLow;
2173 /* Convert timestamps to Unix format. */
2174 buf->st_mtime = convert_time (info.ftLastWriteTime);
2175 buf->st_atime = convert_time (info.ftLastAccessTime);
2176 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
2177 buf->st_ctime = convert_time (info.ftCreationTime);
2178 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
2180 /* determine rwx permissions */
2181 if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
2182 permission = _S_IREAD;
2183 else
2184 permission = _S_IREAD | _S_IWRITE;
2186 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
2187 permission |= _S_IEXEC;
2188 else
2190 #if 0 /* no way of knowing the filename */
2191 char * p = strrchr (name, '.');
2192 if (p != NULL &&
2193 (stricmp (p, ".exe") == 0 ||
2194 stricmp (p, ".com") == 0 ||
2195 stricmp (p, ".bat") == 0 ||
2196 stricmp (p, ".cmd") == 0))
2197 permission |= _S_IEXEC;
2198 #endif
2201 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
2203 return 0;
2207 utime (const char *name, struct utimbuf *times)
2209 struct utimbuf deftime;
2210 HANDLE fh;
2211 FILETIME mtime;
2212 FILETIME atime;
2214 if (times == NULL)
2216 deftime.modtime = deftime.actime = time (NULL);
2217 times = &deftime;
2220 /* Need write access to set times. */
2221 fh = CreateFile (name, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
2222 0, OPEN_EXISTING, 0, NULL);
2223 if (fh)
2225 convert_from_time_t (times->actime, &atime);
2226 convert_from_time_t (times->modtime, &mtime);
2227 if (!SetFileTime (fh, NULL, &atime, &mtime))
2229 CloseHandle (fh);
2230 errno = EACCES;
2231 return -1;
2233 CloseHandle (fh);
2235 else
2237 errno = EINVAL;
2238 return -1;
2240 return 0;
2243 #ifdef HAVE_SOCKETS
2245 /* Wrappers for winsock functions to map between our file descriptors
2246 and winsock's handles; also set h_errno for convenience.
2248 To allow Emacs to run on systems which don't have winsock support
2249 installed, we dynamically link to winsock on startup if present, and
2250 otherwise provide the minimum necessary functionality
2251 (eg. gethostname). */
2253 /* function pointers for relevant socket functions */
2254 int (PASCAL *pfn_WSAStartup) (WORD wVersionRequired, LPWSADATA lpWSAData);
2255 void (PASCAL *pfn_WSASetLastError) (int iError);
2256 int (PASCAL *pfn_WSAGetLastError) (void);
2257 int (PASCAL *pfn_socket) (int af, int type, int protocol);
2258 int (PASCAL *pfn_bind) (SOCKET s, const struct sockaddr *addr, int namelen);
2259 int (PASCAL *pfn_connect) (SOCKET s, const struct sockaddr *addr, int namelen);
2260 int (PASCAL *pfn_ioctlsocket) (SOCKET s, long cmd, u_long *argp);
2261 int (PASCAL *pfn_recv) (SOCKET s, char * buf, int len, int flags);
2262 int (PASCAL *pfn_send) (SOCKET s, const char * buf, int len, int flags);
2263 int (PASCAL *pfn_closesocket) (SOCKET s);
2264 int (PASCAL *pfn_shutdown) (SOCKET s, int how);
2265 int (PASCAL *pfn_WSACleanup) (void);
2267 u_short (PASCAL *pfn_htons) (u_short hostshort);
2268 u_short (PASCAL *pfn_ntohs) (u_short netshort);
2269 unsigned long (PASCAL *pfn_inet_addr) (const char * cp);
2270 int (PASCAL *pfn_gethostname) (char * name, int namelen);
2271 struct hostent * (PASCAL *pfn_gethostbyname) (const char * name);
2272 struct servent * (PASCAL *pfn_getservbyname) (const char * name, const char * proto);
2274 /* SetHandleInformation is only needed to make sockets non-inheritable. */
2275 BOOL (WINAPI *pfn_SetHandleInformation) (HANDLE object, DWORD mask, DWORD flags);
2276 #ifndef HANDLE_FLAG_INHERIT
2277 #define HANDLE_FLAG_INHERIT 1
2278 #endif
2280 HANDLE winsock_lib;
2281 static int winsock_inuse;
2283 BOOL
2284 term_winsock (void)
2286 if (winsock_lib != NULL && winsock_inuse == 0)
2288 /* Not sure what would cause WSAENETDOWN, or even if it can happen
2289 after WSAStartup returns successfully, but it seems reasonable
2290 to allow unloading winsock anyway in that case. */
2291 if (pfn_WSACleanup () == 0 ||
2292 pfn_WSAGetLastError () == WSAENETDOWN)
2294 if (FreeLibrary (winsock_lib))
2295 winsock_lib = NULL;
2296 return TRUE;
2299 return FALSE;
2302 BOOL
2303 init_winsock (int load_now)
2305 WSADATA winsockData;
2307 if (winsock_lib != NULL)
2308 return TRUE;
2310 pfn_SetHandleInformation = NULL;
2311 pfn_SetHandleInformation
2312 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
2313 "SetHandleInformation");
2315 winsock_lib = LoadLibrary ("wsock32.dll");
2317 if (winsock_lib != NULL)
2319 /* dynamically link to socket functions */
2321 #define LOAD_PROC(fn) \
2322 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
2323 goto fail;
2325 LOAD_PROC( WSAStartup );
2326 LOAD_PROC( WSASetLastError );
2327 LOAD_PROC( WSAGetLastError );
2328 LOAD_PROC( socket );
2329 LOAD_PROC( bind );
2330 LOAD_PROC( connect );
2331 LOAD_PROC( ioctlsocket );
2332 LOAD_PROC( recv );
2333 LOAD_PROC( send );
2334 LOAD_PROC( closesocket );
2335 LOAD_PROC( shutdown );
2336 LOAD_PROC( htons );
2337 LOAD_PROC( ntohs );
2338 LOAD_PROC( inet_addr );
2339 LOAD_PROC( gethostname );
2340 LOAD_PROC( gethostbyname );
2341 LOAD_PROC( getservbyname );
2342 LOAD_PROC( WSACleanup );
2344 #undef LOAD_PROC
2346 /* specify version 1.1 of winsock */
2347 if (pfn_WSAStartup (0x101, &winsockData) == 0)
2349 if (winsockData.wVersion != 0x101)
2350 goto fail;
2352 if (!load_now)
2354 /* Report that winsock exists and is usable, but leave
2355 socket functions disabled. I am assuming that calling
2356 WSAStartup does not require any network interaction,
2357 and in particular does not cause or require a dial-up
2358 connection to be established. */
2360 pfn_WSACleanup ();
2361 FreeLibrary (winsock_lib);
2362 winsock_lib = NULL;
2364 winsock_inuse = 0;
2365 return TRUE;
2368 fail:
2369 FreeLibrary (winsock_lib);
2370 winsock_lib = NULL;
2373 return FALSE;
2377 int h_errno = 0;
2379 /* function to set h_errno for compatability; map winsock error codes to
2380 normal system codes where they overlap (non-overlapping definitions
2381 are already in <sys/socket.h> */
2382 static void set_errno ()
2384 if (winsock_lib == NULL)
2385 h_errno = EINVAL;
2386 else
2387 h_errno = pfn_WSAGetLastError ();
2389 switch (h_errno)
2391 case WSAEACCES: h_errno = EACCES; break;
2392 case WSAEBADF: h_errno = EBADF; break;
2393 case WSAEFAULT: h_errno = EFAULT; break;
2394 case WSAEINTR: h_errno = EINTR; break;
2395 case WSAEINVAL: h_errno = EINVAL; break;
2396 case WSAEMFILE: h_errno = EMFILE; break;
2397 case WSAENAMETOOLONG: h_errno = ENAMETOOLONG; break;
2398 case WSAENOTEMPTY: h_errno = ENOTEMPTY; break;
2400 errno = h_errno;
2403 static void check_errno ()
2405 if (h_errno == 0 && winsock_lib != NULL)
2406 pfn_WSASetLastError (0);
2409 /* Extend strerror to handle the winsock-specific error codes. */
2410 struct {
2411 int errnum;
2412 char * msg;
2413 } _wsa_errlist[] = {
2414 WSAEINTR , "Interrupted function call",
2415 WSAEBADF , "Bad file descriptor",
2416 WSAEACCES , "Permission denied",
2417 WSAEFAULT , "Bad address",
2418 WSAEINVAL , "Invalid argument",
2419 WSAEMFILE , "Too many open files",
2421 WSAEWOULDBLOCK , "Resource temporarily unavailable",
2422 WSAEINPROGRESS , "Operation now in progress",
2423 WSAEALREADY , "Operation already in progress",
2424 WSAENOTSOCK , "Socket operation on non-socket",
2425 WSAEDESTADDRREQ , "Destination address required",
2426 WSAEMSGSIZE , "Message too long",
2427 WSAEPROTOTYPE , "Protocol wrong type for socket",
2428 WSAENOPROTOOPT , "Bad protocol option",
2429 WSAEPROTONOSUPPORT , "Protocol not supported",
2430 WSAESOCKTNOSUPPORT , "Socket type not supported",
2431 WSAEOPNOTSUPP , "Operation not supported",
2432 WSAEPFNOSUPPORT , "Protocol family not supported",
2433 WSAEAFNOSUPPORT , "Address family not supported by protocol family",
2434 WSAEADDRINUSE , "Address already in use",
2435 WSAEADDRNOTAVAIL , "Cannot assign requested address",
2436 WSAENETDOWN , "Network is down",
2437 WSAENETUNREACH , "Network is unreachable",
2438 WSAENETRESET , "Network dropped connection on reset",
2439 WSAECONNABORTED , "Software caused connection abort",
2440 WSAECONNRESET , "Connection reset by peer",
2441 WSAENOBUFS , "No buffer space available",
2442 WSAEISCONN , "Socket is already connected",
2443 WSAENOTCONN , "Socket is not connected",
2444 WSAESHUTDOWN , "Cannot send after socket shutdown",
2445 WSAETOOMANYREFS , "Too many references", /* not sure */
2446 WSAETIMEDOUT , "Connection timed out",
2447 WSAECONNREFUSED , "Connection refused",
2448 WSAELOOP , "Network loop", /* not sure */
2449 WSAENAMETOOLONG , "Name is too long",
2450 WSAEHOSTDOWN , "Host is down",
2451 WSAEHOSTUNREACH , "No route to host",
2452 WSAENOTEMPTY , "Buffer not empty", /* not sure */
2453 WSAEPROCLIM , "Too many processes",
2454 WSAEUSERS , "Too many users", /* not sure */
2455 WSAEDQUOT , "Double quote in host name", /* really not sure */
2456 WSAESTALE , "Data is stale", /* not sure */
2457 WSAEREMOTE , "Remote error", /* not sure */
2459 WSASYSNOTREADY , "Network subsystem is unavailable",
2460 WSAVERNOTSUPPORTED , "WINSOCK.DLL version out of range",
2461 WSANOTINITIALISED , "Winsock not initialized successfully",
2462 WSAEDISCON , "Graceful shutdown in progress",
2463 #ifdef WSAENOMORE
2464 WSAENOMORE , "No more operations allowed", /* not sure */
2465 WSAECANCELLED , "Operation cancelled", /* not sure */
2466 WSAEINVALIDPROCTABLE , "Invalid procedure table from service provider",
2467 WSAEINVALIDPROVIDER , "Invalid service provider version number",
2468 WSAEPROVIDERFAILEDINIT , "Unable to initialize a service provider",
2469 WSASYSCALLFAILURE , "System call failured",
2470 WSASERVICE_NOT_FOUND , "Service not found", /* not sure */
2471 WSATYPE_NOT_FOUND , "Class type not found",
2472 WSA_E_NO_MORE , "No more resources available", /* really not sure */
2473 WSA_E_CANCELLED , "Operation already cancelled", /* really not sure */
2474 WSAEREFUSED , "Operation refused", /* not sure */
2475 #endif
2477 WSAHOST_NOT_FOUND , "Host not found",
2478 WSATRY_AGAIN , "Authoritative host not found during name lookup",
2479 WSANO_RECOVERY , "Non-recoverable error during name lookup",
2480 WSANO_DATA , "Valid name, no data record of requested type",
2482 -1, NULL
2485 char *
2486 sys_strerror(int error_no)
2488 int i;
2489 static char unknown_msg[40];
2491 if (error_no >= 0 && error_no < _sys_nerr)
2492 return _sys_errlist[error_no];
2494 for (i = 0; _wsa_errlist[i].errnum >= 0; i++)
2495 if (_wsa_errlist[i].errnum == error_no)
2496 return _wsa_errlist[i].msg;
2498 sprintf(unknown_msg, "Unidentified error: %d", error_no);
2499 return unknown_msg;
2502 /* [andrewi 3-May-96] I've had conflicting results using both methods,
2503 but I believe the method of keeping the socket handle separate (and
2504 insuring it is not inheritable) is the correct one. */
2506 //#define SOCK_REPLACE_HANDLE
2508 #ifdef SOCK_REPLACE_HANDLE
2509 #define SOCK_HANDLE(fd) ((SOCKET) _get_osfhandle (fd))
2510 #else
2511 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
2512 #endif
2515 sys_socket(int af, int type, int protocol)
2517 int fd;
2518 long s;
2519 child_process * cp;
2521 if (winsock_lib == NULL)
2523 h_errno = ENETDOWN;
2524 return INVALID_SOCKET;
2527 check_errno ();
2529 /* call the real socket function */
2530 s = (long) pfn_socket (af, type, protocol);
2532 if (s != INVALID_SOCKET)
2534 /* Although under NT 3.5 _open_osfhandle will accept a socket
2535 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
2536 that does not work under NT 3.1. However, we can get the same
2537 effect by using a backdoor function to replace an existing
2538 descriptor handle with the one we want. */
2540 /* allocate a file descriptor (with appropriate flags) */
2541 fd = _open ("NUL:", _O_RDWR);
2542 if (fd >= 0)
2544 #ifdef SOCK_REPLACE_HANDLE
2545 /* now replace handle to NUL with our socket handle */
2546 CloseHandle ((HANDLE) _get_osfhandle (fd));
2547 _free_osfhnd (fd);
2548 _set_osfhnd (fd, s);
2549 /* setmode (fd, _O_BINARY); */
2550 #else
2551 /* Make a non-inheritable copy of the socket handle. */
2553 HANDLE parent;
2554 HANDLE new_s = INVALID_HANDLE_VALUE;
2556 parent = GetCurrentProcess ();
2558 /* Apparently there is a bug in NT 3.51 with some service
2559 packs, which prevents using DuplicateHandle to make a
2560 socket handle non-inheritable (causes WSACleanup to
2561 hang). The work-around is to use SetHandleInformation
2562 instead if it is available and implemented. */
2563 if (!pfn_SetHandleInformation
2564 || !pfn_SetHandleInformation ((HANDLE) s,
2565 HANDLE_FLAG_INHERIT,
2568 DuplicateHandle (parent,
2569 (HANDLE) s,
2570 parent,
2571 &new_s,
2573 FALSE,
2574 DUPLICATE_SAME_ACCESS);
2575 pfn_closesocket (s);
2576 s = (SOCKET) new_s;
2578 fd_info[fd].hnd = (HANDLE) s;
2580 #endif
2582 /* set our own internal flags */
2583 fd_info[fd].flags = FILE_SOCKET | FILE_BINARY | FILE_READ | FILE_WRITE;
2585 cp = new_child ();
2586 if (cp)
2588 cp->fd = fd;
2589 cp->status = STATUS_READ_ACKNOWLEDGED;
2591 /* attach child_process to fd_info */
2592 if (fd_info[ fd ].cp != NULL)
2594 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd));
2595 abort ();
2598 fd_info[ fd ].cp = cp;
2600 /* success! */
2601 winsock_inuse++; /* count open sockets */
2602 return fd;
2605 /* clean up */
2606 _close (fd);
2608 pfn_closesocket (s);
2609 h_errno = EMFILE;
2611 set_errno ();
2613 return -1;
2618 sys_bind (int s, const struct sockaddr * addr, int namelen)
2620 if (winsock_lib == NULL)
2622 h_errno = ENOTSOCK;
2623 return SOCKET_ERROR;
2626 check_errno ();
2627 if (fd_info[s].flags & FILE_SOCKET)
2629 int rc = pfn_bind (SOCK_HANDLE (s), addr, namelen);
2630 if (rc == SOCKET_ERROR)
2631 set_errno ();
2632 return rc;
2634 h_errno = ENOTSOCK;
2635 return SOCKET_ERROR;
2640 sys_connect (int s, const struct sockaddr * name, int namelen)
2642 if (winsock_lib == NULL)
2644 h_errno = ENOTSOCK;
2645 return SOCKET_ERROR;
2648 check_errno ();
2649 if (fd_info[s].flags & FILE_SOCKET)
2651 int rc = pfn_connect (SOCK_HANDLE (s), name, namelen);
2652 if (rc == SOCKET_ERROR)
2653 set_errno ();
2654 return rc;
2656 h_errno = ENOTSOCK;
2657 return SOCKET_ERROR;
2660 u_short
2661 sys_htons (u_short hostshort)
2663 return (winsock_lib != NULL) ?
2664 pfn_htons (hostshort) : hostshort;
2667 u_short
2668 sys_ntohs (u_short netshort)
2670 return (winsock_lib != NULL) ?
2671 pfn_ntohs (netshort) : netshort;
2674 unsigned long
2675 sys_inet_addr (const char * cp)
2677 return (winsock_lib != NULL) ?
2678 pfn_inet_addr (cp) : INADDR_NONE;
2682 sys_gethostname (char * name, int namelen)
2684 if (winsock_lib != NULL)
2685 return pfn_gethostname (name, namelen);
2687 if (namelen > MAX_COMPUTERNAME_LENGTH)
2688 return !GetComputerName (name, &namelen);
2690 h_errno = EFAULT;
2691 return SOCKET_ERROR;
2694 struct hostent *
2695 sys_gethostbyname(const char * name)
2697 struct hostent * host;
2699 if (winsock_lib == NULL)
2701 h_errno = ENETDOWN;
2702 return NULL;
2705 check_errno ();
2706 host = pfn_gethostbyname (name);
2707 if (!host)
2708 set_errno ();
2709 return host;
2712 struct servent *
2713 sys_getservbyname(const char * name, const char * proto)
2715 struct servent * serv;
2717 if (winsock_lib == NULL)
2719 h_errno = ENETDOWN;
2720 return NULL;
2723 check_errno ();
2724 serv = pfn_getservbyname (name, proto);
2725 if (!serv)
2726 set_errno ();
2727 return serv;
2731 sys_shutdown (int s, int how)
2733 int rc;
2735 if (winsock_lib == NULL)
2737 h_errno = ENETDOWN;
2738 return SOCKET_ERROR;
2741 check_errno ();
2742 if (fd_info[s].flags & FILE_SOCKET)
2744 int rc = pfn_shutdown (SOCK_HANDLE (s), how);
2745 if (rc == SOCKET_ERROR)
2746 set_errno ();
2747 return rc;
2749 h_errno = ENOTSOCK;
2750 return SOCKET_ERROR;
2753 #endif /* HAVE_SOCKETS */
2756 /* Shadow main io functions: we need to handle pipes and sockets more
2757 intelligently, and implement non-blocking mode as well. */
2760 sys_close (int fd)
2762 int rc;
2764 if (fd < 0 || fd >= MAXDESC)
2766 errno = EBADF;
2767 return -1;
2770 if (fd_info[fd].cp)
2772 child_process * cp = fd_info[fd].cp;
2774 fd_info[fd].cp = NULL;
2776 if (CHILD_ACTIVE (cp))
2778 /* if last descriptor to active child_process then cleanup */
2779 int i;
2780 for (i = 0; i < MAXDESC; i++)
2782 if (i == fd)
2783 continue;
2784 if (fd_info[i].cp == cp)
2785 break;
2787 if (i == MAXDESC)
2789 #ifdef HAVE_SOCKETS
2790 if (fd_info[fd].flags & FILE_SOCKET)
2792 #ifndef SOCK_REPLACE_HANDLE
2793 if (winsock_lib == NULL) abort ();
2795 pfn_shutdown (SOCK_HANDLE (fd), 2);
2796 rc = pfn_closesocket (SOCK_HANDLE (fd));
2797 #endif
2798 winsock_inuse--; /* count open sockets */
2800 #endif
2801 delete_child (cp);
2806 /* Note that sockets do not need special treatment here (at least on
2807 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
2808 closesocket is equivalent to CloseHandle, which is to be expected
2809 because socket handles are fully fledged kernel handles. */
2810 rc = _close (fd);
2812 if (rc == 0)
2813 fd_info[fd].flags = 0;
2815 return rc;
2819 sys_dup (int fd)
2821 int new_fd;
2823 new_fd = _dup (fd);
2824 if (new_fd >= 0)
2826 /* duplicate our internal info as well */
2827 fd_info[new_fd] = fd_info[fd];
2829 return new_fd;
2834 sys_dup2 (int src, int dst)
2836 int rc;
2838 if (dst < 0 || dst >= MAXDESC)
2840 errno = EBADF;
2841 return -1;
2844 /* make sure we close the destination first if it's a pipe or socket */
2845 if (src != dst && fd_info[dst].flags != 0)
2846 sys_close (dst);
2848 rc = _dup2 (src, dst);
2849 if (rc == 0)
2851 /* duplicate our internal info as well */
2852 fd_info[dst] = fd_info[src];
2854 return rc;
2857 /* Unix pipe() has only one arg */
2859 sys_pipe (int * phandles)
2861 int rc;
2862 unsigned flags;
2863 child_process * cp;
2865 /* make pipe handles non-inheritable; when we spawn a child, we
2866 replace the relevant handle with an inheritable one. Also put
2867 pipes into binary mode; we will do text mode translation ourselves
2868 if required. */
2869 rc = _pipe (phandles, 0, _O_NOINHERIT | _O_BINARY);
2871 if (rc == 0)
2873 flags = FILE_PIPE | FILE_READ | FILE_BINARY;
2874 fd_info[phandles[0]].flags = flags;
2876 flags = FILE_PIPE | FILE_WRITE | FILE_BINARY;
2877 fd_info[phandles[1]].flags = flags;
2880 return rc;
2883 /* From ntproc.c */
2884 extern Lisp_Object Vw32_pipe_read_delay;
2886 /* Function to do blocking read of one byte, needed to implement
2887 select. It is only allowed on sockets and pipes. */
2889 _sys_read_ahead (int fd)
2891 child_process * cp;
2892 int rc;
2894 if (fd < 0 || fd >= MAXDESC)
2895 return STATUS_READ_ERROR;
2897 cp = fd_info[fd].cp;
2899 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
2900 return STATUS_READ_ERROR;
2902 if ((fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET)) == 0
2903 || (fd_info[fd].flags & FILE_READ) == 0)
2905 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe or socket!\n", fd));
2906 abort ();
2909 cp->status = STATUS_READ_IN_PROGRESS;
2911 if (fd_info[fd].flags & FILE_PIPE)
2913 rc = _read (fd, &cp->chr, sizeof (char));
2915 /* Give subprocess time to buffer some more output for us before
2916 reporting that input is available; we need this because Windows 95
2917 connects DOS programs to pipes by making the pipe appear to be
2918 the normal console stdout - as a result most DOS programs will
2919 write to stdout without buffering, ie. one character at a
2920 time. Even some W32 programs do this - "dir" in a command
2921 shell on NT is very slow if we don't do this. */
2922 if (rc > 0)
2924 int wait = XINT (Vw32_pipe_read_delay);
2926 if (wait > 0)
2927 Sleep (wait);
2928 else if (wait < 0)
2929 while (++wait <= 0)
2930 /* Yield remainder of our time slice, effectively giving a
2931 temporary priority boost to the child process. */
2932 Sleep (0);
2935 #ifdef HAVE_SOCKETS
2936 else if (fd_info[fd].flags & FILE_SOCKET)
2937 rc = pfn_recv (SOCK_HANDLE (fd), &cp->chr, sizeof (char), 0);
2938 #endif
2940 if (rc == sizeof (char))
2941 cp->status = STATUS_READ_SUCCEEDED;
2942 else
2943 cp->status = STATUS_READ_FAILED;
2945 return cp->status;
2949 sys_read (int fd, char * buffer, unsigned int count)
2951 int nchars;
2952 int to_read;
2953 DWORD waiting;
2954 char * orig_buffer = buffer;
2956 if (fd < 0 || fd >= MAXDESC)
2958 errno = EBADF;
2959 return -1;
2962 if (fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET))
2964 child_process *cp = fd_info[fd].cp;
2966 if ((fd_info[fd].flags & FILE_READ) == 0)
2968 errno = EBADF;
2969 return -1;
2972 nchars = 0;
2974 /* re-read CR carried over from last read */
2975 if (fd_info[fd].flags & FILE_LAST_CR)
2977 if (fd_info[fd].flags & FILE_BINARY) abort ();
2978 *buffer++ = 0x0d;
2979 count--;
2980 nchars++;
2981 fd_info[fd].flags &= ~FILE_LAST_CR;
2984 /* presence of a child_process structure means we are operating in
2985 non-blocking mode - otherwise we just call _read directly.
2986 Note that the child_process structure might be missing because
2987 reap_subprocess has been called; in this case the pipe is
2988 already broken, so calling _read on it is okay. */
2989 if (cp)
2991 int current_status = cp->status;
2993 switch (current_status)
2995 case STATUS_READ_FAILED:
2996 case STATUS_READ_ERROR:
2997 /* report normal EOF if nothing in buffer */
2998 if (nchars <= 0)
2999 fd_info[fd].flags |= FILE_AT_EOF;
3000 return nchars;
3002 case STATUS_READ_READY:
3003 case STATUS_READ_IN_PROGRESS:
3004 DebPrint (("sys_read called when read is in progress\n"));
3005 errno = EWOULDBLOCK;
3006 return -1;
3008 case STATUS_READ_SUCCEEDED:
3009 /* consume read-ahead char */
3010 *buffer++ = cp->chr;
3011 count--;
3012 nchars++;
3013 cp->status = STATUS_READ_ACKNOWLEDGED;
3014 ResetEvent (cp->char_avail);
3016 case STATUS_READ_ACKNOWLEDGED:
3017 break;
3019 default:
3020 DebPrint (("sys_read: bad status %d\n", current_status));
3021 errno = EBADF;
3022 return -1;
3025 if (fd_info[fd].flags & FILE_PIPE)
3027 PeekNamedPipe ((HANDLE) _get_osfhandle (fd), NULL, 0, NULL, &waiting, NULL);
3028 to_read = min (waiting, (DWORD) count);
3030 if (to_read > 0)
3031 nchars += _read (fd, buffer, to_read);
3033 #ifdef HAVE_SOCKETS
3034 else /* FILE_SOCKET */
3036 if (winsock_lib == NULL) abort ();
3038 /* do the equivalent of a non-blocking read */
3039 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONREAD, &waiting);
3040 if (waiting == 0 && nchars == 0)
3042 h_errno = errno = EWOULDBLOCK;
3043 return -1;
3046 if (waiting)
3048 /* always use binary mode for sockets */
3049 int res = pfn_recv (SOCK_HANDLE (fd), buffer, count, 0);
3050 if (res == SOCKET_ERROR)
3052 DebPrint(("sys_read.recv failed with error %d on socket %ld\n",
3053 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
3054 set_errno ();
3055 return -1;
3057 nchars += res;
3060 #endif
3062 else
3064 int nread = _read (fd, buffer, count);
3065 if (nread >= 0)
3066 nchars += nread;
3067 else if (nchars == 0)
3068 nchars = nread;
3071 if (nchars <= 0)
3072 fd_info[fd].flags |= FILE_AT_EOF;
3073 /* Perform text mode translation if required. */
3074 else if ((fd_info[fd].flags & FILE_BINARY) == 0)
3076 nchars = crlf_to_lf (nchars, orig_buffer);
3077 /* If buffer contains only CR, return that. To be absolutely
3078 sure we should attempt to read the next char, but in
3079 practice a CR to be followed by LF would not appear by
3080 itself in the buffer. */
3081 if (nchars > 1 && orig_buffer[nchars - 1] == 0x0d)
3083 fd_info[fd].flags |= FILE_LAST_CR;
3084 nchars--;
3088 else
3089 nchars = _read (fd, buffer, count);
3091 return nchars;
3094 /* For now, don't bother with a non-blocking mode */
3096 sys_write (int fd, const void * buffer, unsigned int count)
3098 int nchars;
3100 if (fd < 0 || fd >= MAXDESC)
3102 errno = EBADF;
3103 return -1;
3106 if (fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET))
3108 if ((fd_info[fd].flags & FILE_WRITE) == 0)
3110 errno = EBADF;
3111 return -1;
3114 /* Perform text mode translation if required. */
3115 if ((fd_info[fd].flags & FILE_BINARY) == 0)
3117 char * tmpbuf = alloca (count * 2);
3118 unsigned char * src = (void *)buffer;
3119 unsigned char * dst = tmpbuf;
3120 int nbytes = count;
3122 while (1)
3124 unsigned char *next;
3125 /* copy next line or remaining bytes */
3126 next = _memccpy (dst, src, '\n', nbytes);
3127 if (next)
3129 /* copied one line ending with '\n' */
3130 int copied = next - dst;
3131 nbytes -= copied;
3132 src += copied;
3133 /* insert '\r' before '\n' */
3134 next[-1] = '\r';
3135 next[0] = '\n';
3136 dst = next + 1;
3137 count++;
3139 else
3140 /* copied remaining partial line -> now finished */
3141 break;
3143 buffer = tmpbuf;
3147 #ifdef HAVE_SOCKETS
3148 if (fd_info[fd].flags & FILE_SOCKET)
3150 if (winsock_lib == NULL) abort ();
3151 nchars = pfn_send (SOCK_HANDLE (fd), buffer, count, 0);
3152 if (nchars == SOCKET_ERROR)
3154 DebPrint(("sys_read.send failed with error %d on socket %ld\n",
3155 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
3156 set_errno ();
3159 else
3160 #endif
3161 nchars = _write (fd, buffer, count);
3163 return nchars;
3166 static void
3167 check_windows_init_file ()
3169 extern int noninteractive, inhibit_window_system;
3171 /* A common indication that Emacs is not installed properly is when
3172 it cannot find the Windows installation file. If this file does
3173 not exist in the expected place, tell the user. */
3175 if (!noninteractive && !inhibit_window_system)
3177 extern Lisp_Object Vwindow_system, Vload_path, Qfile_exists_p;
3178 Lisp_Object objs[2];
3179 Lisp_Object full_load_path;
3180 Lisp_Object init_file;
3181 int fd;
3183 objs[0] = Vload_path;
3184 objs[1] = decode_env_path (0, (getenv ("EMACSLOADPATH")));
3185 full_load_path = Fappend (2, objs);
3186 init_file = build_string ("term/w32-win");
3187 fd = openp (full_load_path, init_file, ".el:.elc", NULL, 0);
3188 if (fd < 0)
3190 Lisp_Object load_path_print = Fprin1_to_string (full_load_path, Qnil);
3191 char *init_file_name = XSTRING (init_file)->data;
3192 char *load_path = XSTRING (load_path_print)->data;
3193 char *buffer = alloca (1024);
3195 sprintf (buffer,
3196 "The Emacs Windows initialization file \"%s.el\" "
3197 "could not be found in your Emacs installation. "
3198 "Emacs checked the following directories for this file:\n"
3199 "\n%s\n\n"
3200 "When Emacs cannot find this file, it usually means that it "
3201 "was not installed properly, or its distribution file was "
3202 "not unpacked properly.\nSee the README.W32 file in the "
3203 "top-level Emacs directory for more information.",
3204 init_file_name, load_path);
3205 MessageBox (NULL,
3206 buffer,
3207 "Emacs Abort Dialog",
3208 MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
3209 /* Use the low-level Emacs abort. */
3210 #undef abort
3211 abort ();
3213 else
3215 close (fd);
3220 void
3221 term_ntproc ()
3223 #ifdef HAVE_SOCKETS
3224 /* shutdown the socket interface if necessary */
3225 term_winsock ();
3226 #endif
3229 void
3230 init_ntproc ()
3232 #ifdef HAVE_SOCKETS
3233 /* Initialise the socket interface now if available and requested by
3234 the user by defining PRELOAD_WINSOCK; otherwise loading will be
3235 delayed until open-network-stream is called (w32-has-winsock can
3236 also be used to dynamically load or reload winsock).
3238 Conveniently, init_environment is called before us, so
3239 PRELOAD_WINSOCK can be set in the registry. */
3241 /* Always initialize this correctly. */
3242 winsock_lib = NULL;
3244 if (getenv ("PRELOAD_WINSOCK") != NULL)
3245 init_winsock (TRUE);
3246 #endif
3248 /* Initial preparation for subprocess support: replace our standard
3249 handles with non-inheritable versions. */
3251 HANDLE parent;
3252 HANDLE stdin_save = INVALID_HANDLE_VALUE;
3253 HANDLE stdout_save = INVALID_HANDLE_VALUE;
3254 HANDLE stderr_save = INVALID_HANDLE_VALUE;
3256 parent = GetCurrentProcess ();
3258 /* ignore errors when duplicating and closing; typically the
3259 handles will be invalid when running as a gui program. */
3260 DuplicateHandle (parent,
3261 GetStdHandle (STD_INPUT_HANDLE),
3262 parent,
3263 &stdin_save,
3265 FALSE,
3266 DUPLICATE_SAME_ACCESS);
3268 DuplicateHandle (parent,
3269 GetStdHandle (STD_OUTPUT_HANDLE),
3270 parent,
3271 &stdout_save,
3273 FALSE,
3274 DUPLICATE_SAME_ACCESS);
3276 DuplicateHandle (parent,
3277 GetStdHandle (STD_ERROR_HANDLE),
3278 parent,
3279 &stderr_save,
3281 FALSE,
3282 DUPLICATE_SAME_ACCESS);
3284 fclose (stdin);
3285 fclose (stdout);
3286 fclose (stderr);
3288 if (stdin_save != INVALID_HANDLE_VALUE)
3289 _open_osfhandle ((long) stdin_save, O_TEXT);
3290 else
3291 _open ("nul", O_TEXT | O_NOINHERIT | O_RDONLY);
3292 _fdopen (0, "r");
3294 if (stdout_save != INVALID_HANDLE_VALUE)
3295 _open_osfhandle ((long) stdout_save, O_TEXT);
3296 else
3297 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
3298 _fdopen (1, "w");
3300 if (stderr_save != INVALID_HANDLE_VALUE)
3301 _open_osfhandle ((long) stderr_save, O_TEXT);
3302 else
3303 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
3304 _fdopen (2, "w");
3307 /* unfortunately, atexit depends on implementation of malloc */
3308 /* atexit (term_ntproc); */
3309 signal (SIGABRT, term_ntproc);
3311 /* determine which drives are fixed, for GetCachedVolumeInformation */
3313 /* GetDriveType must have trailing backslash. */
3314 char drive[] = "A:\\";
3316 /* Loop over all possible drive letters */
3317 while (*drive <= 'Z')
3319 /* Record if this drive letter refers to a fixed drive. */
3320 fixed_drives[DRIVE_INDEX (*drive)] =
3321 (GetDriveType (drive) == DRIVE_FIXED);
3323 (*drive)++;
3327 /* Check to see if Emacs has been installed correctly. */
3328 check_windows_init_file ();
3331 /* end of nt.c */