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)
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 */
35 #include <sys/utime.h>
37 /* must include CRT headers *before* config.h */
66 #ifdef HAVE_SOCKETS /* TCP connection support, if kernel can do it */
67 #include <sys/socket.h>
86 #define min(x, y) (((x) < (y)) ? (x) : (y))
87 #define max(x, y) (((x) > (y)) ? (x) : (y))
89 extern Lisp_Object Vw32_downcase_file_names
;
90 extern Lisp_Object Vw32_generate_fake_inodes
;
91 extern Lisp_Object Vw32_get_true_file_attributes
;
93 static char startup_dir
[MAXPATHLEN
];
95 /* Get the current working directory. */
100 if (GetCurrentDirectory (MAXPATHLEN
, dir
) > 0)
104 /* Emacs doesn't actually change directory itself, and we want to
105 force our real wd to be where emacs.exe is to avoid unnecessary
106 conflicts when trying to rename or delete directories. */
107 strcpy (dir
, startup_dir
);
113 /* Emulate gethostname. */
115 gethostname (char *buffer
, int size
)
117 /* NT only allows small host names, so the buffer is
118 certainly large enough. */
119 return !GetComputerName (buffer
, &size
);
121 #endif /* HAVE_SOCKETS */
123 /* Emulate getloadavg. */
125 getloadavg (double loadavg
[], int nelem
)
129 /* A faithful emulation is going to have to be saved for a rainy day. */
130 for (i
= 0; i
< nelem
; i
++)
137 /* Emulate getpwuid, getpwnam and others. */
139 #define PASSWD_FIELD_SIZE 256
141 static char the_passwd_name
[PASSWD_FIELD_SIZE
];
142 static char the_passwd_passwd
[PASSWD_FIELD_SIZE
];
143 static char the_passwd_gecos
[PASSWD_FIELD_SIZE
];
144 static char the_passwd_dir
[PASSWD_FIELD_SIZE
];
145 static char the_passwd_shell
[PASSWD_FIELD_SIZE
];
147 static struct passwd the_passwd
=
162 return the_passwd
.pw_uid
;
168 /* I could imagine arguing for checking to see whether the user is
169 in the Administrators group and returning a UID of 0 for that
170 case, but I don't know how wise that would be in the long run. */
177 return the_passwd
.pw_gid
;
189 if (uid
== the_passwd
.pw_uid
)
195 getpwnam (char *name
)
199 pw
= getpwuid (getuid ());
203 if (stricmp (name
, pw
->pw_name
))
212 /* Find the user's real name by opening the process token and
213 looking up the name associated with the user-sid in that token.
215 Use the relative portion of the identifier authority value from
216 the user-sid as the user id value (same for group id using the
217 primary group sid from the process token). */
219 char user_sid
[256], name
[256], domain
[256];
220 DWORD length
= sizeof (name
), dlength
= sizeof (domain
), trash
;
222 SID_NAME_USE user_type
;
224 if (OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY
, &token
)
225 && GetTokenInformation (token
, TokenUser
,
226 (PVOID
) user_sid
, sizeof (user_sid
), &trash
)
227 && LookupAccountSid (NULL
, *((PSID
*) user_sid
), name
, &length
,
228 domain
, &dlength
, &user_type
))
230 strcpy (the_passwd
.pw_name
, name
);
231 /* Determine a reasonable uid value. */
232 if (stricmp ("administrator", name
) == 0)
234 the_passwd
.pw_uid
= 0;
235 the_passwd
.pw_gid
= 0;
239 SID_IDENTIFIER_AUTHORITY
* pSIA
;
241 pSIA
= GetSidIdentifierAuthority (*((PSID
*) user_sid
));
242 /* I believe the relative portion is the last 4 bytes (of 6)
244 the_passwd
.pw_uid
= ((pSIA
->Value
[2] << 24) +
245 (pSIA
->Value
[3] << 16) +
246 (pSIA
->Value
[4] << 8) +
247 (pSIA
->Value
[5] << 0));
248 /* restrict to conventional uid range for normal users */
249 the_passwd
.pw_uid
= the_passwd
.pw_uid
% 60001;
252 if (GetTokenInformation (token
, TokenPrimaryGroup
,
253 (PVOID
) user_sid
, sizeof (user_sid
), &trash
))
255 SID_IDENTIFIER_AUTHORITY
* pSIA
;
257 pSIA
= GetSidIdentifierAuthority (*((PSID
*) user_sid
));
258 the_passwd
.pw_gid
= ((pSIA
->Value
[2] << 24) +
259 (pSIA
->Value
[3] << 16) +
260 (pSIA
->Value
[4] << 8) +
261 (pSIA
->Value
[5] << 0));
262 /* I don't know if this is necessary, but for safety... */
263 the_passwd
.pw_gid
= the_passwd
.pw_gid
% 60001;
266 the_passwd
.pw_gid
= the_passwd
.pw_uid
;
269 /* If security calls are not supported (presumably because we
270 are running under Windows 95), fallback to this. */
271 else if (GetUserName (name
, &length
))
273 strcpy (the_passwd
.pw_name
, name
);
274 if (stricmp ("administrator", name
) == 0)
275 the_passwd
.pw_uid
= 0;
277 the_passwd
.pw_uid
= 123;
278 the_passwd
.pw_gid
= the_passwd
.pw_uid
;
282 strcpy (the_passwd
.pw_name
, "unknown");
283 the_passwd
.pw_uid
= 123;
284 the_passwd
.pw_gid
= 123;
287 /* Ensure HOME and SHELL are defined. */
288 if (getenv ("HOME") == NULL
)
290 if (getenv ("SHELL") == NULL
)
291 putenv (os_subtype
== OS_WIN95
? "SHELL=command" : "SHELL=cmd");
293 /* Set dir and shell from environment variables. */
294 strcpy (the_passwd
.pw_dir
, getenv ("HOME"));
295 strcpy (the_passwd
.pw_shell
, getenv ("SHELL"));
304 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
305 return ((rand () << 15) | rand ());
315 /* Normalize filename by converting all path separators to
316 the specified separator. Also conditionally convert upper
317 case path name components to lower case. */
320 normalize_filename (fp
, path_sep
)
327 /* Always lower-case drive letters a-z, even if the filesystem
328 preserves case in filenames.
329 This is so filenames can be compared by string comparison
330 functions that are case-sensitive. Even case-preserving filesystems
331 do not distinguish case in drive letters. */
332 if (fp
[1] == ':' && *fp
>= 'A' && *fp
<= 'Z')
338 if (NILP (Vw32_downcase_file_names
))
342 if (*fp
== '/' || *fp
== '\\')
349 sep
= path_sep
; /* convert to this path separator */
350 elem
= fp
; /* start of current path element */
353 if (*fp
>= 'a' && *fp
<= 'z')
354 elem
= 0; /* don't convert this element */
356 if (*fp
== 0 || *fp
== ':')
358 sep
= *fp
; /* restore current separator (or 0) */
359 *fp
= '/'; /* after conversion of this element */
362 if (*fp
== '/' || *fp
== '\\')
364 if (elem
&& elem
!= fp
)
366 *fp
= 0; /* temporary end of string */
367 _strlwr (elem
); /* while we convert to lower case */
369 *fp
= sep
; /* convert (or restore) path separator */
370 elem
= fp
+ 1; /* next element starts after separator */
376 /* Destructively turn backslashes into slashes. */
378 dostounix_filename (p
)
381 normalize_filename (p
, '/');
384 /* Destructively turn slashes into backslashes. */
386 unixtodos_filename (p
)
389 normalize_filename (p
, '\\');
392 /* Remove all CR's that are followed by a LF.
393 (From msdos.c...probably should figure out a way to share it,
394 although this code isn't going to ever change.) */
398 register unsigned char *buf
;
400 unsigned char *np
= buf
;
401 unsigned char *startp
= buf
;
402 unsigned char *endp
= buf
+ n
;
406 while (buf
< endp
- 1)
410 if (*(++buf
) != 0x0a)
421 /* Parse the root part of file name, if present. Return length and
422 optionally store pointer to char after root. */
424 parse_root (char * name
, char ** pPath
)
431 /* find the root name of the volume if given */
432 if (isalpha (name
[0]) && name
[1] == ':')
434 /* skip past drive specifier */
436 if (IS_DIRECTORY_SEP (name
[0]))
439 else if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
445 if (IS_DIRECTORY_SEP (*name
) && --slashes
== 0)
450 if (IS_DIRECTORY_SEP (name
[0]))
460 /* Get long base name for name; name is assumed to be absolute. */
462 get_long_basename (char * name
, char * buf
, int size
)
464 WIN32_FIND_DATA find_data
;
468 /* must be valid filename, no wild cards or other illegal characters */
469 if (strpbrk (name
, "*?|<>\""))
472 dir_handle
= FindFirstFile (name
, &find_data
);
473 if (dir_handle
!= INVALID_HANDLE_VALUE
)
475 if ((len
= strlen (find_data
.cFileName
)) < size
)
476 memcpy (buf
, find_data
.cFileName
, len
+ 1);
479 FindClose (dir_handle
);
484 /* Get long name for file, if possible (assumed to be absolute). */
486 w32_get_long_filename (char * name
, char * buf
, int size
)
491 char full
[ MAX_PATH
];
498 /* Use local copy for destructive modification. */
499 memcpy (full
, name
, len
+1);
500 unixtodos_filename (full
);
502 /* Copy root part verbatim. */
503 len
= parse_root (full
, &p
);
504 memcpy (o
, full
, len
);
511 p
= strchr (q
, '\\');
513 len
= get_long_basename (full
, o
, size
);
531 while (p
!= NULL
&& *p
);
537 /* Routines that are no-ops on NT but are defined to get Emacs to compile. */
540 sigsetmask (int signal_mask
)
552 setpgrp (int pid
, int gid
)
564 unrequest_sigio (void)
575 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
578 w32_get_resource (key
, lpdwtype
)
583 HKEY hrootkey
= NULL
;
587 /* Check both the current user and the local machine to see if
588 we have any resources. */
590 if (RegOpenKeyEx (HKEY_CURRENT_USER
, REG_ROOT
, 0, KEY_READ
, &hrootkey
) == ERROR_SUCCESS
)
594 if (RegQueryValueEx (hrootkey
, key
, NULL
, NULL
, NULL
, &cbData
) == ERROR_SUCCESS
595 && (lpvalue
= (LPBYTE
) xmalloc (cbData
)) != NULL
596 && RegQueryValueEx (hrootkey
, key
, NULL
, lpdwtype
, lpvalue
, &cbData
) == ERROR_SUCCESS
)
601 if (lpvalue
) xfree (lpvalue
);
603 RegCloseKey (hrootkey
);
606 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE
, REG_ROOT
, 0, KEY_READ
, &hrootkey
) == ERROR_SUCCESS
)
610 if (RegQueryValueEx (hrootkey
, key
, NULL
, NULL
, NULL
, &cbData
) == ERROR_SUCCESS
611 && (lpvalue
= (LPBYTE
) xmalloc (cbData
)) != NULL
612 && RegQueryValueEx (hrootkey
, key
, NULL
, lpdwtype
, lpvalue
, &cbData
) == ERROR_SUCCESS
)
617 if (lpvalue
) xfree (lpvalue
);
619 RegCloseKey (hrootkey
);
625 char *get_emacs_configuration (void);
626 extern Lisp_Object Vsystem_configuration
;
632 static const char * const tempdirs
[] = {
633 "$TMPDIR", "$TEMP", "$TMP", "c:/"
636 const int imax
= sizeof (tempdirs
) / sizeof (tempdirs
[0]);
638 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
639 temporary files and assume "/tmp" if $TMPDIR is unset, which
640 will break on DOS/Windows. Refuse to work if we cannot find
641 a directory, not even "c:/", usable for that purpose. */
642 for (i
= 0; i
< imax
; i
++)
644 const char *tmp
= tempdirs
[i
];
647 tmp
= getenv (tmp
+ 1);
648 /* Note that `access' can lie to us if the directory resides on a
649 read-only filesystem, like CD-ROM or a write-protected floppy.
650 The only way to be really sure is to actually create a file and
651 see if it succeeds. But I think that's too much to ask. */
652 if (tmp
&& access (tmp
, D_OK
) == 0)
654 char * var
= alloca (strlen (tmp
) + 8);
655 sprintf (var
, "TMPDIR=%s", tmp
);
663 Fcons (build_string ("no usable temporary directories found!!"),
665 "While setting TMPDIR: ");
667 /* Check for environment variables and use registry if they don't exist */
673 static char * env_vars
[] =
684 /* We no longer set INFOPATH because Info-default-directory-list
685 is then ignored. We use a hook in winnt.el instead. */
691 for (i
= 0; i
< (sizeof (env_vars
) / sizeof (env_vars
[0])); i
++)
693 if (!getenv (env_vars
[i
])
694 && (lpval
= w32_get_resource (env_vars
[i
], &dwType
)) != NULL
)
696 if (dwType
== REG_EXPAND_SZ
)
698 char buf1
[500], buf2
[500];
700 ExpandEnvironmentStrings ((LPSTR
) lpval
, buf1
, 500);
701 _snprintf (buf2
, 499, "%s=%s", env_vars
[i
], buf1
);
702 putenv (strdup (buf2
));
704 else if (dwType
== REG_SZ
)
708 _snprintf (buf
, 499, "%s=%s", env_vars
[i
], lpval
);
709 putenv (strdup (buf
));
717 /* Rebuild system configuration to reflect invoking system. */
718 Vsystem_configuration
= build_string (EMACS_CONFIGURATION
);
720 /* Another special case: on NT, the PATH variable is actually named
721 "Path" although cmd.exe (perhaps NT itself) arranges for
722 environment variable lookup and setting to be case insensitive.
723 However, Emacs assumes a fully case sensitive environment, so we
724 need to change "Path" to "PATH" to match the expectations of
725 various elisp packages. We do this by the sneaky method of
726 modifying the string in the C runtime environ entry.
728 The same applies to COMSPEC. */
732 for (envp
= environ
; *envp
; envp
++)
733 if (_strnicmp (*envp
, "PATH=", 5) == 0)
734 memcpy (*envp
, "PATH=", 5);
735 else if (_strnicmp (*envp
, "COMSPEC=", 8) == 0)
736 memcpy (*envp
, "COMSPEC=", 8);
739 /* Remember the initial working directory for getwd, then make the
740 real wd be the location of emacs.exe to avoid conflicts when
741 renaming or deleting directories. (We also don't call chdir when
742 running subprocesses for the same reason.) */
743 if (!GetCurrentDirectory (MAXPATHLEN
, startup_dir
))
748 char modname
[MAX_PATH
];
750 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
752 if ((p
= strrchr (modname
, '\\')) == NULL
)
756 SetCurrentDirectory (modname
);
762 /* We don't have scripts to automatically determine the system configuration
763 for Emacs before it's compiled, and we don't want to have to make the
764 user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
767 static char configuration_buffer
[32];
770 get_emacs_configuration (void)
772 char *arch
, *oem
, *os
;
774 /* Determine the processor type. */
775 switch (get_processor_type ())
778 #ifdef PROCESSOR_INTEL_386
779 case PROCESSOR_INTEL_386
:
780 case PROCESSOR_INTEL_486
:
781 case PROCESSOR_INTEL_PENTIUM
:
786 #ifdef PROCESSOR_INTEL_860
787 case PROCESSOR_INTEL_860
:
792 #ifdef PROCESSOR_MIPS_R2000
793 case PROCESSOR_MIPS_R2000
:
794 case PROCESSOR_MIPS_R3000
:
795 case PROCESSOR_MIPS_R4000
:
800 #ifdef PROCESSOR_ALPHA_21064
801 case PROCESSOR_ALPHA_21064
:
811 /* Let oem be "*" until we figure out how to decode the OEM field. */
814 os
= (GetVersion () & OS_WIN95
) ? "windows95" : "nt";
816 sprintf (configuration_buffer
, "%s-%s-%s%d.%d", arch
, oem
, os
,
817 get_w32_major_version (), get_w32_minor_version ());
818 return configuration_buffer
;
821 #include <sys/timeb.h>
823 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
825 gettimeofday (struct timeval
*tv
, struct timezone
*tz
)
830 tv
->tv_sec
= tb
.time
;
831 tv
->tv_usec
= tb
.millitm
* 1000L;
834 tz
->tz_minuteswest
= tb
.timezone
; /* minutes west of Greenwich */
835 tz
->tz_dsttime
= tb
.dstflag
; /* type of dst correction */
839 /* ------------------------------------------------------------------------- */
840 /* IO support and wrapper functions for W32 API. */
841 /* ------------------------------------------------------------------------- */
843 /* Place a wrapper around the MSVC version of ctime. It returns NULL
844 on network directories, so we handle that case here.
845 (Ulrich Leodolter, 1/11/95). */
847 sys_ctime (const time_t *t
)
849 char *str
= (char *) ctime (t
);
850 return (str
? str
: "Sun Jan 01 00:00:00 1970");
853 /* Emulate sleep...we could have done this with a define, but that
854 would necessitate including windows.h in the files that used it.
855 This is much easier. */
857 sys_sleep (int seconds
)
859 Sleep (seconds
* 1000);
862 /* Internal MSVC functions for low-level descriptor munging */
863 extern int __cdecl
_set_osfhnd (int fd
, long h
);
864 extern int __cdecl
_free_osfhnd (int fd
);
866 /* parallel array of private info on file handles */
867 filedesc fd_info
[ MAXDESC
];
869 typedef struct volume_info_data
{
870 struct volume_info_data
* next
;
872 /* time when info was obtained */
875 /* actual volume info */
884 /* Global referenced by various functions. */
885 static volume_info_data volume_info
;
887 /* Vector to indicate which drives are local and fixed (for which cached
888 data never expires). */
889 static BOOL fixed_drives
[26];
891 /* Consider cached volume information to be stale if older than 10s,
892 at least for non-local drives. Info for fixed drives is never stale. */
893 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
894 #define VOLINFO_STILL_VALID( root_dir, info ) \
895 ( ( isalpha (root_dir[0]) && \
896 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
897 || GetTickCount () - info->timestamp < 10000 )
899 /* Cache support functions. */
901 /* Simple linked list with linear search is sufficient. */
902 static volume_info_data
*volume_cache
= NULL
;
904 static volume_info_data
*
905 lookup_volume_info (char * root_dir
)
907 volume_info_data
* info
;
909 for (info
= volume_cache
; info
; info
= info
->next
)
910 if (stricmp (info
->root_dir
, root_dir
) == 0)
916 add_volume_info (char * root_dir
, volume_info_data
* info
)
918 info
->root_dir
= strdup (root_dir
);
919 info
->next
= volume_cache
;
924 /* Wrapper for GetVolumeInformation, which uses caching to avoid
925 performance penalty (~2ms on 486 for local drives, 7.5ms for local
926 cdrom drive, ~5-10ms or more for remote drives on LAN). */
928 GetCachedVolumeInformation (char * root_dir
)
930 volume_info_data
* info
;
931 char default_root
[ MAX_PATH
];
933 /* NULL for root_dir means use root from current directory. */
934 if (root_dir
== NULL
)
936 if (GetCurrentDirectory (MAX_PATH
, default_root
) == 0)
938 parse_root (default_root
, &root_dir
);
940 root_dir
= default_root
;
943 /* Local fixed drives can be cached permanently. Removable drives
944 cannot be cached permanently, since the volume name and serial
945 number (if nothing else) can change. Remote drives should be
946 treated as if they are removable, since there is no sure way to
947 tell whether they are or not. Also, the UNC association of drive
948 letters mapped to remote volumes can be changed at any time (even
949 by other processes) without notice.
951 As a compromise, so we can benefit from caching info for remote
952 volumes, we use a simple expiry mechanism to invalidate cache
953 entries that are more than ten seconds old. */
956 /* No point doing this, because WNetGetConnection is even slower than
957 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
958 GetDriveType is about the only call of this type which does not
959 involve network access, and so is extremely quick). */
961 /* Map drive letter to UNC if remote. */
962 if ( isalpha( root_dir
[0] ) && !fixed
[ DRIVE_INDEX( root_dir
[0] ) ] )
964 char remote_name
[ 256 ];
965 char drive
[3] = { root_dir
[0], ':' };
967 if (WNetGetConnection (drive
, remote_name
, sizeof (remote_name
))
973 info
= lookup_volume_info (root_dir
);
975 if (info
== NULL
|| ! VOLINFO_STILL_VALID (root_dir
, info
))
983 /* Info is not cached, or is stale. */
984 if (!GetVolumeInformation (root_dir
,
989 type
, sizeof (type
)))
992 /* Cache the volume information for future use, overwriting existing
996 info
= (volume_info_data
*) xmalloc (sizeof (volume_info_data
));
997 add_volume_info (root_dir
, info
);
1005 info
->name
= strdup (name
);
1006 info
->serialnum
= serialnum
;
1007 info
->maxcomp
= maxcomp
;
1008 info
->flags
= flags
;
1009 info
->type
= strdup (type
);
1010 info
->timestamp
= GetTickCount ();
1016 /* Get information on the volume where name is held; set path pointer to
1017 start of pathname in name (past UNC header\volume header if present). */
1019 get_volume_info (const char * name
, const char ** pPath
)
1021 char temp
[MAX_PATH
];
1022 char *rootname
= NULL
; /* default to current volume */
1023 volume_info_data
* info
;
1028 /* find the root name of the volume if given */
1029 if (isalpha (name
[0]) && name
[1] == ':')
1037 else if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
1044 if (IS_DIRECTORY_SEP (*name
) && --slashes
== 0)
1057 info
= GetCachedVolumeInformation (rootname
);
1060 /* Set global referenced by other functions. */
1061 volume_info
= *info
;
1067 /* Determine if volume is FAT format (ie. only supports short 8.3
1068 names); also set path pointer to start of pathname in name. */
1070 is_fat_volume (const char * name
, const char ** pPath
)
1072 if (get_volume_info (name
, pPath
))
1073 return (volume_info
.maxcomp
== 12);
1077 /* Map filename to a legal 8.3 name if necessary. */
1079 map_w32_filename (const char * name
, const char ** pPath
)
1081 static char shortname
[MAX_PATH
];
1082 char * str
= shortname
;
1085 const char * save_name
= name
;
1087 if (is_fat_volume (name
, &path
)) /* truncate to 8.3 */
1089 register int left
= 8; /* maximum number of chars in part */
1090 register int extn
= 0; /* extension added? */
1091 register int dots
= 2; /* maximum number of dots allowed */
1094 *str
++ = *name
++; /* skip past UNC header */
1096 while ((c
= *name
++))
1103 extn
= 0; /* reset extension flags */
1104 dots
= 2; /* max 2 dots */
1105 left
= 8; /* max length 8 for main part */
1109 extn
= 0; /* reset extension flags */
1110 dots
= 2; /* max 2 dots */
1111 left
= 8; /* max length 8 for main part */
1116 /* Convert path components of the form .xxx to _xxx,
1117 but leave . and .. as they are. This allows .emacs
1118 to be read as _emacs, for example. */
1122 IS_DIRECTORY_SEP (*name
))
1137 extn
= 1; /* we've got an extension */
1138 left
= 3; /* 3 chars in extension */
1142 /* any embedded dots after the first are converted to _ */
1147 case '#': /* don't lose these, they're important */
1149 str
[-1] = c
; /* replace last character of part */
1154 *str
++ = tolower (c
); /* map to lower case (looks nicer) */
1156 dots
= 0; /* started a path component */
1165 strcpy (shortname
, name
);
1166 unixtodos_filename (shortname
);
1170 *pPath
= shortname
+ (path
- save_name
);
1176 is_exec (const char * name
)
1178 char * p
= strrchr (name
, '.');
1181 && (stricmp (p
, ".exe") == 0 ||
1182 stricmp (p
, ".com") == 0 ||
1183 stricmp (p
, ".bat") == 0 ||
1184 stricmp (p
, ".cmd") == 0));
1187 /* Emulate the Unix directory procedures opendir, closedir,
1188 and readdir. We can't use the procedures supplied in sysdep.c,
1189 so we provide them here. */
1191 struct direct dir_static
; /* simulated directory contents */
1192 static HANDLE dir_find_handle
= INVALID_HANDLE_VALUE
;
1193 static int dir_is_fat
;
1194 static char dir_pathname
[MAXPATHLEN
+1];
1195 static WIN32_FIND_DATA dir_find_data
;
1198 opendir (char *filename
)
1202 /* Opening is done by FindFirstFile. However, a read is inherent to
1203 this operation, so we defer the open until read time. */
1205 if (!(dirp
= (DIR *) malloc (sizeof (DIR))))
1207 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
1214 strncpy (dir_pathname
, map_w32_filename (filename
, NULL
), MAXPATHLEN
);
1215 dir_pathname
[MAXPATHLEN
] = '\0';
1216 dir_is_fat
= is_fat_volume (filename
, NULL
);
1222 closedir (DIR *dirp
)
1224 /* If we have a find-handle open, close it. */
1225 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
1227 FindClose (dir_find_handle
);
1228 dir_find_handle
= INVALID_HANDLE_VALUE
;
1230 xfree ((char *) dirp
);
1236 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
1237 if (dir_find_handle
== INVALID_HANDLE_VALUE
)
1239 char filename
[MAXNAMLEN
+ 3];
1242 strcpy (filename
, dir_pathname
);
1243 ln
= strlen (filename
) - 1;
1244 if (!IS_DIRECTORY_SEP (filename
[ln
]))
1245 strcat (filename
, "\\");
1246 strcat (filename
, "*");
1248 dir_find_handle
= FindFirstFile (filename
, &dir_find_data
);
1250 if (dir_find_handle
== INVALID_HANDLE_VALUE
)
1255 if (!FindNextFile (dir_find_handle
, &dir_find_data
))
1259 /* Emacs never uses this value, so don't bother making it match
1260 value returned by stat(). */
1261 dir_static
.d_ino
= 1;
1263 dir_static
.d_reclen
= sizeof (struct direct
) - MAXNAMLEN
+ 3 +
1264 dir_static
.d_namlen
- dir_static
.d_namlen
% 4;
1266 dir_static
.d_namlen
= strlen (dir_find_data
.cFileName
);
1267 strcpy (dir_static
.d_name
, dir_find_data
.cFileName
);
1269 _strlwr (dir_static
.d_name
);
1270 else if (!NILP (Vw32_downcase_file_names
))
1273 for (p
= dir_static
.d_name
; *p
; p
++)
1274 if (*p
>= 'a' && *p
<= 'z')
1277 _strlwr (dir_static
.d_name
);
1284 /* Shadow some MSVC runtime functions to map requests for long filenames
1285 to reasonable short names if necessary. This was originally added to
1286 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
1290 sys_access (const char * path
, int mode
)
1294 /* MSVC implementation doesn't recognize D_OK. */
1295 path
= map_w32_filename (path
, NULL
);
1296 if ((attributes
= GetFileAttributes (path
)) == -1)
1298 /* Should try mapping GetLastError to errno; for now just indicate
1299 that path doesn't exist. */
1303 if ((mode
& X_OK
) != 0 && !is_exec (path
))
1308 if ((mode
& W_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_READONLY
) != 0)
1313 if ((mode
& D_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_DIRECTORY
) == 0)
1322 sys_chdir (const char * path
)
1324 return _chdir (map_w32_filename (path
, NULL
));
1328 sys_chmod (const char * path
, int mode
)
1330 return _chmod (map_w32_filename (path
, NULL
), mode
);
1334 sys_creat (const char * path
, int mode
)
1336 return _creat (map_w32_filename (path
, NULL
), mode
);
1340 sys_fopen(const char * path
, const char * mode
)
1344 const char * mode_save
= mode
;
1346 /* Force all file handles to be non-inheritable. This is necessary to
1347 ensure child processes don't unwittingly inherit handles that might
1348 prevent future file access. */
1352 else if (mode
[0] == 'w' || mode
[0] == 'a')
1353 oflag
= O_WRONLY
| O_CREAT
| O_TRUNC
;
1357 /* Only do simplistic option parsing. */
1361 oflag
&= ~(O_RDONLY
| O_WRONLY
);
1364 else if (mode
[0] == 'b')
1369 else if (mode
[0] == 't')
1376 fd
= _open (map_w32_filename (path
, NULL
), oflag
| _O_NOINHERIT
, 0644);
1380 return _fdopen (fd
, mode_save
);
1383 /* This only works on NTFS volumes, but is useful to have. */
1385 sys_link (const char * old
, const char * new)
1389 char oldname
[MAX_PATH
], newname
[MAX_PATH
];
1391 if (old
== NULL
|| new == NULL
)
1397 strcpy (oldname
, map_w32_filename (old
, NULL
));
1398 strcpy (newname
, map_w32_filename (new, NULL
));
1400 fileh
= CreateFile (oldname
, 0, 0, NULL
, OPEN_EXISTING
,
1401 FILE_FLAG_BACKUP_SEMANTICS
, NULL
);
1402 if (fileh
!= INVALID_HANDLE_VALUE
)
1406 /* Confusingly, the "alternate" stream name field does not apply
1407 when restoring a hard link, and instead contains the actual
1408 stream data for the link (ie. the name of the link to create).
1409 The WIN32_STREAM_ID structure before the cStreamName field is
1410 the stream header, which is then immediately followed by the
1414 WIN32_STREAM_ID wid
;
1415 WCHAR wbuffer
[MAX_PATH
]; /* extra space for link name */
1418 wlen
= MultiByteToWideChar (CP_ACP
, MB_PRECOMPOSED
, newname
, -1,
1419 data
.wid
.cStreamName
, MAX_PATH
);
1422 LPVOID context
= NULL
;
1425 data
.wid
.dwStreamId
= BACKUP_LINK
;
1426 data
.wid
.dwStreamAttributes
= 0;
1427 data
.wid
.Size
.LowPart
= wlen
* sizeof(WCHAR
);
1428 data
.wid
.Size
.HighPart
= 0;
1429 data
.wid
.dwStreamNameSize
= 0;
1431 if (BackupWrite (fileh
, (LPBYTE
)&data
,
1432 offsetof (WIN32_STREAM_ID
, cStreamName
)
1433 + data
.wid
.Size
.LowPart
,
1434 &wbytes
, FALSE
, FALSE
, &context
)
1435 && BackupWrite (fileh
, NULL
, 0, &wbytes
, TRUE
, FALSE
, &context
))
1442 /* Should try mapping GetLastError to errno; for now just
1443 indicate a general error (eg. links not supported). */
1444 errno
= EINVAL
; // perhaps EMLINK?
1448 CloseHandle (fileh
);
1457 sys_mkdir (const char * path
)
1459 return _mkdir (map_w32_filename (path
, NULL
));
1462 /* Because of long name mapping issues, we need to implement this
1463 ourselves. Also, MSVC's _mktemp returns NULL when it can't generate
1464 a unique name, instead of setting the input template to an empty
1467 Standard algorithm seems to be use pid or tid with a letter on the
1468 front (in place of the 6 X's) and cycle through the letters to find a
1469 unique name. We extend that to allow any reasonable character as the
1470 first of the 6 X's. */
1472 sys_mktemp (char * template)
1476 unsigned uid
= GetCurrentThreadId ();
1477 static char first_char
[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
1479 if (template == NULL
)
1481 p
= template + strlen (template);
1483 /* replace up to the last 5 X's with uid in decimal */
1484 while (--p
>= template && p
[0] == 'X' && --i
>= 0)
1486 p
[0] = '0' + uid
% 10;
1490 if (i
< 0 && p
[0] == 'X')
1495 int save_errno
= errno
;
1496 p
[0] = first_char
[i
];
1497 if (sys_access (template, 0) < 0)
1503 while (++i
< sizeof (first_char
));
1506 /* Template is badly formed or else we can't generate a unique name,
1507 so return empty string */
1513 sys_open (const char * path
, int oflag
, int mode
)
1515 /* Force all file handles to be non-inheritable. */
1516 return _open (map_w32_filename (path
, NULL
), oflag
| _O_NOINHERIT
, mode
);
1520 sys_rename (const char * oldname
, const char * newname
)
1523 char temp
[MAX_PATH
];
1525 /* MoveFile on Windows 95 doesn't correctly change the short file name
1526 alias in a number of circumstances (it is not easy to predict when
1527 just by looking at oldname and newname, unfortunately). In these
1528 cases, renaming through a temporary name avoids the problem.
1530 A second problem on Windows 95 is that renaming through a temp name when
1531 newname is uppercase fails (the final long name ends up in
1532 lowercase, although the short alias might be uppercase) UNLESS the
1533 long temp name is not 8.3.
1535 So, on Windows 95 we always rename through a temp name, and we make sure
1536 the temp name has a long extension to ensure correct renaming. */
1538 strcpy (temp
, map_w32_filename (oldname
, NULL
));
1540 if (os_subtype
== OS_WIN95
)
1546 oldname
= map_w32_filename (oldname
, NULL
);
1547 if (o
= strrchr (oldname
, '\\'))
1550 o
= (char *) oldname
;
1552 if (p
= strrchr (temp
, '\\'))
1559 /* Force temp name to require a manufactured 8.3 alias - this
1560 seems to make the second rename work properly. */
1561 sprintf (p
, ".%s.%u", o
, i
);
1563 result
= rename (oldname
, temp
);
1565 /* This loop must surely terminate! */
1566 while (result
< 0 && errno
== EEXIST
);
1571 /* Emulate Unix behaviour - newname is deleted if it already exists
1572 (at least if it is a file; don't do this for directories).
1574 Since we mustn't do this if we are just changing the case of the
1575 file name (we would end up deleting the file we are trying to
1576 rename!), we let rename detect if the destination file already
1577 exists - that way we avoid the possible pitfalls of trying to
1578 determine ourselves whether two names really refer to the same
1579 file, which is not always possible in the general case. (Consider
1580 all the permutations of shared or subst'd drives, etc.) */
1582 newname
= map_w32_filename (newname
, NULL
);
1583 result
= rename (temp
, newname
);
1587 && _chmod (newname
, 0666) == 0
1588 && _unlink (newname
) == 0)
1589 result
= rename (temp
, newname
);
1595 sys_rmdir (const char * path
)
1597 return _rmdir (map_w32_filename (path
, NULL
));
1601 sys_unlink (const char * path
)
1603 path
= map_w32_filename (path
, NULL
);
1605 /* On Unix, unlink works without write permission. */
1606 _chmod (path
, 0666);
1607 return _unlink (path
);
1610 static FILETIME utc_base_ft
;
1611 static long double utc_base
;
1612 static int init
= 0;
1615 convert_time (FILETIME ft
)
1621 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
1630 st
.wMilliseconds
= 0;
1632 SystemTimeToFileTime (&st
, &utc_base_ft
);
1633 utc_base
= (long double) utc_base_ft
.dwHighDateTime
1634 * 4096 * 1024 * 1024 + utc_base_ft
.dwLowDateTime
;
1638 if (CompareFileTime (&ft
, &utc_base_ft
) < 0)
1641 ret
= (long double) ft
.dwHighDateTime
* 4096 * 1024 * 1024 + ft
.dwLowDateTime
;
1643 return (time_t) (ret
* 1e-7);
1647 convert_from_time_t (time_t time
, FILETIME
* pft
)
1653 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
1662 st
.wMilliseconds
= 0;
1664 SystemTimeToFileTime (&st
, &utc_base_ft
);
1665 utc_base
= (long double) utc_base_ft
.dwHighDateTime
1666 * 4096 * 1024 * 1024 + utc_base_ft
.dwLowDateTime
;
1670 /* time in 100ns units since 1-Jan-1601 */
1671 tmp
= (long double) time
* 1e7
+ utc_base
;
1672 pft
->dwHighDateTime
= (DWORD
) (tmp
/ (4096.0 * 1024 * 1024));
1673 pft
->dwLowDateTime
= (DWORD
) (tmp
- (4096.0 * 1024 * 1024) * pft
->dwHighDateTime
);
1677 /* No reason to keep this; faking inode values either by hashing or even
1678 using the file index from GetInformationByHandle, is not perfect and
1679 so by default Emacs doesn't use the inode values on Windows.
1680 Instead, we now determine file-truename correctly (except for
1681 possible drive aliasing etc). */
1683 /* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
1685 hashval (const unsigned char * str
)
1690 h
= (h
<< 4) + *str
++;
1696 /* Return the hash value of the canonical pathname, excluding the
1697 drive/UNC header, to get a hopefully unique inode number. */
1699 generate_inode_val (const char * name
)
1701 char fullname
[ MAX_PATH
];
1705 /* Get the truly canonical filename, if it exists. (Note: this
1706 doesn't resolve aliasing due to subst commands, or recognise hard
1708 if (!w32_get_long_filename ((char *)name
, fullname
, MAX_PATH
))
1711 parse_root (fullname
, &p
);
1712 /* Normal W32 filesystems are still case insensitive. */
1719 /* MSVC stat function can't cope with UNC names and has other bugs, so
1720 replace it with our own. This also allows us to calculate consistent
1721 inode values without hacks in the main Emacs code. */
1723 stat (const char * path
, struct stat
* buf
)
1726 WIN32_FIND_DATA wfd
;
1731 int rootdir
= FALSE
;
1733 if (path
== NULL
|| buf
== NULL
)
1739 name
= (char *) map_w32_filename (path
, &path
);
1740 /* must be valid filename, no wild cards or other illegal characters */
1741 if (strpbrk (name
, "*?|<>\""))
1747 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
1748 r
= IS_DEVICE_SEP (name
[1]) ? &name
[2] : name
;
1749 if (IS_DIRECTORY_SEP (r
[0]) && r
[1] == '.' && r
[2] == '.' && r
[3] == '\0')
1754 /* Remove trailing directory separator, unless name is the root
1755 directory of a drive or UNC volume in which case ensure there
1756 is a trailing separator. */
1757 len
= strlen (name
);
1758 rootdir
= (path
>= name
+ len
- 1
1759 && (IS_DIRECTORY_SEP (*path
) || *path
== 0));
1760 name
= strcpy (alloca (len
+ 2), name
);
1764 if (!IS_DIRECTORY_SEP (name
[len
-1]))
1765 strcat (name
, "\\");
1766 if (GetDriveType (name
) < 2)
1771 memset (&wfd
, 0, sizeof (wfd
));
1772 wfd
.dwFileAttributes
= FILE_ATTRIBUTE_DIRECTORY
;
1773 wfd
.ftCreationTime
= utc_base_ft
;
1774 wfd
.ftLastAccessTime
= utc_base_ft
;
1775 wfd
.ftLastWriteTime
= utc_base_ft
;
1776 strcpy (wfd
.cFileName
, name
);
1780 if (IS_DIRECTORY_SEP (name
[len
-1]))
1783 /* (This is hacky, but helps when doing file completions on
1784 network drives.) Optimize by using information available from
1785 active readdir if possible. */
1786 if (dir_find_handle
!= INVALID_HANDLE_VALUE
1787 && (len
= strlen (dir_pathname
)),
1788 strnicmp (name
, dir_pathname
, len
) == 0
1789 && IS_DIRECTORY_SEP (name
[len
])
1790 && stricmp (name
+ len
+ 1, dir_static
.d_name
) == 0)
1792 /* This was the last entry returned by readdir. */
1793 wfd
= dir_find_data
;
1797 fh
= FindFirstFile (name
, &wfd
);
1798 if (fh
== INVALID_HANDLE_VALUE
)
1807 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
1809 buf
->st_mode
= _S_IFDIR
;
1810 buf
->st_nlink
= 2; /* doesn't really matter */
1811 fake_inode
= 0; /* this doesn't either I think */
1813 else if (!NILP (Vw32_get_true_file_attributes
))
1815 /* This is more accurate in terms of gettting the correct number
1816 of links, but is quite slow (it is noticable when Emacs is
1817 making a list of file name completions). */
1818 BY_HANDLE_FILE_INFORMATION info
;
1820 /* No access rights required to get info. */
1821 fh
= CreateFile (name
, 0, 0, NULL
, OPEN_EXISTING
, 0, NULL
);
1823 if (GetFileInformationByHandle (fh
, &info
))
1825 switch (GetFileType (fh
))
1827 case FILE_TYPE_DISK
:
1828 buf
->st_mode
= _S_IFREG
;
1830 case FILE_TYPE_PIPE
:
1831 buf
->st_mode
= _S_IFIFO
;
1833 case FILE_TYPE_CHAR
:
1834 case FILE_TYPE_UNKNOWN
:
1836 buf
->st_mode
= _S_IFCHR
;
1838 buf
->st_nlink
= info
.nNumberOfLinks
;
1839 /* Might as well use file index to fake inode values, but this
1840 is not guaranteed to be unique unless we keep a handle open
1841 all the time (even then there are situations where it is
1842 not unique). Reputedly, there are at most 48 bits of info
1843 (on NTFS, presumably less on FAT). */
1844 fake_inode
= info
.nFileIndexLow
^ info
.nFileIndexHigh
;
1855 /* Don't bother to make this information more accurate. */
1856 buf
->st_mode
= _S_IFREG
;
1862 /* Not sure if there is any point in this. */
1863 if (!NILP (Vw32_generate_fake_inodes
))
1864 fake_inode
= generate_inode_val (name
);
1865 else if (fake_inode
== 0)
1867 /* For want of something better, try to make everything unique. */
1868 static DWORD gen_num
= 0;
1869 fake_inode
= ++gen_num
;
1873 /* MSVC defines _ino_t to be short; other libc's might not. */
1874 if (sizeof (buf
->st_ino
) == 2)
1875 buf
->st_ino
= fake_inode
^ (fake_inode
>> 16);
1877 buf
->st_ino
= fake_inode
;
1879 /* consider files to belong to current user */
1880 buf
->st_uid
= the_passwd
.pw_uid
;
1881 buf
->st_gid
= the_passwd
.pw_gid
;
1883 /* volume_info is set indirectly by map_w32_filename */
1884 buf
->st_dev
= volume_info
.serialnum
;
1885 buf
->st_rdev
= volume_info
.serialnum
;
1888 buf
->st_size
= wfd
.nFileSizeLow
;
1890 /* Convert timestamps to Unix format. */
1891 buf
->st_mtime
= convert_time (wfd
.ftLastWriteTime
);
1892 buf
->st_atime
= convert_time (wfd
.ftLastAccessTime
);
1893 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
1894 buf
->st_ctime
= convert_time (wfd
.ftCreationTime
);
1895 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
1897 /* determine rwx permissions */
1898 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
1899 permission
= _S_IREAD
;
1901 permission
= _S_IREAD
| _S_IWRITE
;
1903 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
1904 permission
|= _S_IEXEC
;
1905 else if (is_exec (name
))
1906 permission
|= _S_IEXEC
;
1908 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
1913 /* Provide fstat and utime as well as stat for consistent handling of
1916 fstat (int desc
, struct stat
* buf
)
1918 HANDLE fh
= (HANDLE
) _get_osfhandle (desc
);
1919 BY_HANDLE_FILE_INFORMATION info
;
1923 switch (GetFileType (fh
) & ~FILE_TYPE_REMOTE
)
1925 case FILE_TYPE_DISK
:
1926 buf
->st_mode
= _S_IFREG
;
1927 if (!GetFileInformationByHandle (fh
, &info
))
1933 case FILE_TYPE_PIPE
:
1934 buf
->st_mode
= _S_IFIFO
;
1936 case FILE_TYPE_CHAR
:
1937 case FILE_TYPE_UNKNOWN
:
1939 buf
->st_mode
= _S_IFCHR
;
1941 memset (&info
, 0, sizeof (info
));
1942 info
.dwFileAttributes
= 0;
1943 info
.ftCreationTime
= utc_base_ft
;
1944 info
.ftLastAccessTime
= utc_base_ft
;
1945 info
.ftLastWriteTime
= utc_base_ft
;
1948 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
1950 buf
->st_mode
= _S_IFDIR
;
1951 buf
->st_nlink
= 2; /* doesn't really matter */
1952 fake_inode
= 0; /* this doesn't either I think */
1956 buf
->st_nlink
= info
.nNumberOfLinks
;
1957 /* Might as well use file index to fake inode values, but this
1958 is not guaranteed to be unique unless we keep a handle open
1959 all the time (even then there are situations where it is
1960 not unique). Reputedly, there are at most 48 bits of info
1961 (on NTFS, presumably less on FAT). */
1962 fake_inode
= info
.nFileIndexLow
^ info
.nFileIndexHigh
;
1965 /* MSVC defines _ino_t to be short; other libc's might not. */
1966 if (sizeof (buf
->st_ino
) == 2)
1967 buf
->st_ino
= fake_inode
^ (fake_inode
>> 16);
1969 buf
->st_ino
= fake_inode
;
1971 /* consider files to belong to current user */
1975 buf
->st_dev
= info
.dwVolumeSerialNumber
;
1976 buf
->st_rdev
= info
.dwVolumeSerialNumber
;
1978 buf
->st_size
= info
.nFileSizeLow
;
1980 /* Convert timestamps to Unix format. */
1981 buf
->st_mtime
= convert_time (info
.ftLastWriteTime
);
1982 buf
->st_atime
= convert_time (info
.ftLastAccessTime
);
1983 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
1984 buf
->st_ctime
= convert_time (info
.ftCreationTime
);
1985 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
1987 /* determine rwx permissions */
1988 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
1989 permission
= _S_IREAD
;
1991 permission
= _S_IREAD
| _S_IWRITE
;
1993 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
1994 permission
|= _S_IEXEC
;
1997 #if 0 /* no way of knowing the filename */
1998 char * p
= strrchr (name
, '.');
2000 (stricmp (p
, ".exe") == 0 ||
2001 stricmp (p
, ".com") == 0 ||
2002 stricmp (p
, ".bat") == 0 ||
2003 stricmp (p
, ".cmd") == 0))
2004 permission
|= _S_IEXEC
;
2008 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
2014 utime (const char *name
, struct utimbuf
*times
)
2016 struct utimbuf deftime
;
2023 deftime
.modtime
= deftime
.actime
= time (NULL
);
2027 /* Need write access to set times. */
2028 fh
= CreateFile (name
, GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
2029 0, OPEN_EXISTING
, 0, NULL
);
2032 convert_from_time_t (times
->actime
, &atime
);
2033 convert_from_time_t (times
->modtime
, &mtime
);
2034 if (!SetFileTime (fh
, NULL
, &atime
, &mtime
))
2052 /* Wrappers for winsock functions to map between our file descriptors
2053 and winsock's handles; also set h_errno for convenience.
2055 To allow Emacs to run on systems which don't have winsock support
2056 installed, we dynamically link to winsock on startup if present, and
2057 otherwise provide the minimum necessary functionality
2058 (eg. gethostname). */
2060 /* function pointers for relevant socket functions */
2061 int (PASCAL
*pfn_WSAStartup
) (WORD wVersionRequired
, LPWSADATA lpWSAData
);
2062 void (PASCAL
*pfn_WSASetLastError
) (int iError
);
2063 int (PASCAL
*pfn_WSAGetLastError
) (void);
2064 int (PASCAL
*pfn_socket
) (int af
, int type
, int protocol
);
2065 int (PASCAL
*pfn_bind
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
2066 int (PASCAL
*pfn_connect
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
2067 int (PASCAL
*pfn_ioctlsocket
) (SOCKET s
, long cmd
, u_long
*argp
);
2068 int (PASCAL
*pfn_recv
) (SOCKET s
, char * buf
, int len
, int flags
);
2069 int (PASCAL
*pfn_send
) (SOCKET s
, const char * buf
, int len
, int flags
);
2070 int (PASCAL
*pfn_closesocket
) (SOCKET s
);
2071 int (PASCAL
*pfn_shutdown
) (SOCKET s
, int how
);
2072 int (PASCAL
*pfn_WSACleanup
) (void);
2074 u_short (PASCAL
*pfn_htons
) (u_short hostshort
);
2075 u_short (PASCAL
*pfn_ntohs
) (u_short netshort
);
2076 unsigned long (PASCAL
*pfn_inet_addr
) (const char * cp
);
2077 int (PASCAL
*pfn_gethostname
) (char * name
, int namelen
);
2078 struct hostent
* (PASCAL
*pfn_gethostbyname
) (const char * name
);
2079 struct servent
* (PASCAL
*pfn_getservbyname
) (const char * name
, const char * proto
);
2081 /* SetHandleInformation is only needed to make sockets non-inheritable. */
2082 BOOL (WINAPI
*pfn_SetHandleInformation
) (HANDLE object
, DWORD mask
, DWORD flags
);
2083 #ifndef HANDLE_FLAG_INHERIT
2084 #define HANDLE_FLAG_INHERIT 1
2088 static int winsock_inuse
;
2093 if (winsock_lib
!= NULL
&& winsock_inuse
== 0)
2095 /* Not sure what would cause WSAENETDOWN, or even if it can happen
2096 after WSAStartup returns successfully, but it seems reasonable
2097 to allow unloading winsock anyway in that case. */
2098 if (pfn_WSACleanup () == 0 ||
2099 pfn_WSAGetLastError () == WSAENETDOWN
)
2101 if (FreeLibrary (winsock_lib
))
2110 init_winsock (int load_now
)
2112 WSADATA winsockData
;
2114 if (winsock_lib
!= NULL
)
2117 pfn_SetHandleInformation
= NULL
;
2118 pfn_SetHandleInformation
2119 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
2120 "SetHandleInformation");
2122 winsock_lib
= LoadLibrary ("wsock32.dll");
2124 if (winsock_lib
!= NULL
)
2126 /* dynamically link to socket functions */
2128 #define LOAD_PROC(fn) \
2129 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
2132 LOAD_PROC( WSAStartup
);
2133 LOAD_PROC( WSASetLastError
);
2134 LOAD_PROC( WSAGetLastError
);
2135 LOAD_PROC( socket
);
2137 LOAD_PROC( connect
);
2138 LOAD_PROC( ioctlsocket
);
2141 LOAD_PROC( closesocket
);
2142 LOAD_PROC( shutdown
);
2145 LOAD_PROC( inet_addr
);
2146 LOAD_PROC( gethostname
);
2147 LOAD_PROC( gethostbyname
);
2148 LOAD_PROC( getservbyname
);
2149 LOAD_PROC( WSACleanup
);
2153 /* specify version 1.1 of winsock */
2154 if (pfn_WSAStartup (0x101, &winsockData
) == 0)
2156 if (winsockData
.wVersion
!= 0x101)
2161 /* Report that winsock exists and is usable, but leave
2162 socket functions disabled. I am assuming that calling
2163 WSAStartup does not require any network interaction,
2164 and in particular does not cause or require a dial-up
2165 connection to be established. */
2168 FreeLibrary (winsock_lib
);
2176 FreeLibrary (winsock_lib
);
2186 /* function to set h_errno for compatability; map winsock error codes to
2187 normal system codes where they overlap (non-overlapping definitions
2188 are already in <sys/socket.h> */
2189 static void set_errno ()
2191 if (winsock_lib
== NULL
)
2194 h_errno
= pfn_WSAGetLastError ();
2198 case WSAEACCES
: h_errno
= EACCES
; break;
2199 case WSAEBADF
: h_errno
= EBADF
; break;
2200 case WSAEFAULT
: h_errno
= EFAULT
; break;
2201 case WSAEINTR
: h_errno
= EINTR
; break;
2202 case WSAEINVAL
: h_errno
= EINVAL
; break;
2203 case WSAEMFILE
: h_errno
= EMFILE
; break;
2204 case WSAENAMETOOLONG
: h_errno
= ENAMETOOLONG
; break;
2205 case WSAENOTEMPTY
: h_errno
= ENOTEMPTY
; break;
2210 static void check_errno ()
2212 if (h_errno
== 0 && winsock_lib
!= NULL
)
2213 pfn_WSASetLastError (0);
2216 /* [andrewi 3-May-96] I've had conflicting results using both methods,
2217 but I believe the method of keeping the socket handle separate (and
2218 insuring it is not inheritable) is the correct one. */
2220 //#define SOCK_REPLACE_HANDLE
2222 #ifdef SOCK_REPLACE_HANDLE
2223 #define SOCK_HANDLE(fd) ((SOCKET) _get_osfhandle (fd))
2225 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
2229 sys_socket(int af
, int type
, int protocol
)
2235 if (winsock_lib
== NULL
)
2238 return INVALID_SOCKET
;
2243 /* call the real socket function */
2244 s
= (long) pfn_socket (af
, type
, protocol
);
2246 if (s
!= INVALID_SOCKET
)
2248 /* Although under NT 3.5 _open_osfhandle will accept a socket
2249 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
2250 that does not work under NT 3.1. However, we can get the same
2251 effect by using a backdoor function to replace an existing
2252 descriptor handle with the one we want. */
2254 /* allocate a file descriptor (with appropriate flags) */
2255 fd
= _open ("NUL:", _O_RDWR
);
2258 #ifdef SOCK_REPLACE_HANDLE
2259 /* now replace handle to NUL with our socket handle */
2260 CloseHandle ((HANDLE
) _get_osfhandle (fd
));
2262 _set_osfhnd (fd
, s
);
2263 /* setmode (fd, _O_BINARY); */
2265 /* Make a non-inheritable copy of the socket handle. */
2268 HANDLE new_s
= INVALID_HANDLE_VALUE
;
2270 parent
= GetCurrentProcess ();
2272 /* Apparently there is a bug in NT 3.51 with some service
2273 packs, which prevents using DuplicateHandle to make a
2274 socket handle non-inheritable (causes WSACleanup to
2275 hang). The work-around is to use SetHandleInformation
2276 instead if it is available and implemented. */
2277 if (!pfn_SetHandleInformation
2278 || !pfn_SetHandleInformation ((HANDLE
) s
,
2279 HANDLE_FLAG_INHERIT
,
2282 DuplicateHandle (parent
,
2288 DUPLICATE_SAME_ACCESS
);
2289 pfn_closesocket (s
);
2292 fd_info
[fd
].hnd
= (HANDLE
) s
;
2296 /* set our own internal flags */
2297 fd_info
[fd
].flags
= FILE_SOCKET
| FILE_BINARY
| FILE_READ
| FILE_WRITE
;
2303 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
2305 /* attach child_process to fd_info */
2306 if (fd_info
[ fd
].cp
!= NULL
)
2308 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd
));
2312 fd_info
[ fd
].cp
= cp
;
2315 winsock_inuse
++; /* count open sockets */
2322 pfn_closesocket (s
);
2332 sys_bind (int s
, const struct sockaddr
* addr
, int namelen
)
2334 if (winsock_lib
== NULL
)
2337 return SOCKET_ERROR
;
2341 if (fd_info
[s
].flags
& FILE_SOCKET
)
2343 int rc
= pfn_bind (SOCK_HANDLE (s
), addr
, namelen
);
2344 if (rc
== SOCKET_ERROR
)
2349 return SOCKET_ERROR
;
2354 sys_connect (int s
, const struct sockaddr
* name
, int namelen
)
2356 if (winsock_lib
== NULL
)
2359 return SOCKET_ERROR
;
2363 if (fd_info
[s
].flags
& FILE_SOCKET
)
2365 int rc
= pfn_connect (SOCK_HANDLE (s
), name
, namelen
);
2366 if (rc
== SOCKET_ERROR
)
2371 return SOCKET_ERROR
;
2375 sys_htons (u_short hostshort
)
2377 return (winsock_lib
!= NULL
) ?
2378 pfn_htons (hostshort
) : hostshort
;
2382 sys_ntohs (u_short netshort
)
2384 return (winsock_lib
!= NULL
) ?
2385 pfn_ntohs (netshort
) : netshort
;
2389 sys_inet_addr (const char * cp
)
2391 return (winsock_lib
!= NULL
) ?
2392 pfn_inet_addr (cp
) : INADDR_NONE
;
2396 sys_gethostname (char * name
, int namelen
)
2398 if (winsock_lib
!= NULL
)
2399 return pfn_gethostname (name
, namelen
);
2401 if (namelen
> MAX_COMPUTERNAME_LENGTH
)
2402 return !GetComputerName (name
, &namelen
);
2405 return SOCKET_ERROR
;
2409 sys_gethostbyname(const char * name
)
2411 struct hostent
* host
;
2413 if (winsock_lib
== NULL
)
2420 host
= pfn_gethostbyname (name
);
2427 sys_getservbyname(const char * name
, const char * proto
)
2429 struct servent
* serv
;
2431 if (winsock_lib
== NULL
)
2438 serv
= pfn_getservbyname (name
, proto
);
2445 sys_shutdown (int s
, int how
)
2449 if (winsock_lib
== NULL
)
2452 return SOCKET_ERROR
;
2456 if (fd_info
[s
].flags
& FILE_SOCKET
)
2458 int rc
= pfn_shutdown (SOCK_HANDLE (s
), how
);
2459 if (rc
== SOCKET_ERROR
)
2464 return SOCKET_ERROR
;
2467 #endif /* HAVE_SOCKETS */
2470 /* Shadow main io functions: we need to handle pipes and sockets more
2471 intelligently, and implement non-blocking mode as well. */
2478 if (fd
< 0 || fd
>= MAXDESC
)
2486 child_process
* cp
= fd_info
[fd
].cp
;
2488 fd_info
[fd
].cp
= NULL
;
2490 if (CHILD_ACTIVE (cp
))
2492 /* if last descriptor to active child_process then cleanup */
2494 for (i
= 0; i
< MAXDESC
; i
++)
2498 if (fd_info
[i
].cp
== cp
)
2504 if (fd_info
[fd
].flags
& FILE_SOCKET
)
2506 #ifndef SOCK_REPLACE_HANDLE
2507 if (winsock_lib
== NULL
) abort ();
2509 pfn_shutdown (SOCK_HANDLE (fd
), 2);
2510 rc
= pfn_closesocket (SOCK_HANDLE (fd
));
2512 winsock_inuse
--; /* count open sockets */
2520 /* Note that sockets do not need special treatment here (at least on
2521 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
2522 closesocket is equivalent to CloseHandle, which is to be expected
2523 because socket handles are fully fledged kernel handles. */
2527 fd_info
[fd
].flags
= 0;
2540 /* duplicate our internal info as well */
2541 fd_info
[new_fd
] = fd_info
[fd
];
2548 sys_dup2 (int src
, int dst
)
2552 if (dst
< 0 || dst
>= MAXDESC
)
2558 /* make sure we close the destination first if it's a pipe or socket */
2559 if (src
!= dst
&& fd_info
[dst
].flags
!= 0)
2562 rc
= _dup2 (src
, dst
);
2565 /* duplicate our internal info as well */
2566 fd_info
[dst
] = fd_info
[src
];
2571 /* Unix pipe() has only one arg */
2573 sys_pipe (int * phandles
)
2579 /* make pipe handles non-inheritable; when we spawn a child, we
2580 replace the relevant handle with an inheritable one. Also put
2581 pipes into binary mode; we will do text mode translation ourselves
2583 rc
= _pipe (phandles
, 0, _O_NOINHERIT
| _O_BINARY
);
2587 flags
= FILE_PIPE
| FILE_READ
| FILE_BINARY
;
2588 fd_info
[phandles
[0]].flags
= flags
;
2590 flags
= FILE_PIPE
| FILE_WRITE
| FILE_BINARY
;
2591 fd_info
[phandles
[1]].flags
= flags
;
2598 extern Lisp_Object Vw32_pipe_read_delay
;
2600 /* Function to do blocking read of one byte, needed to implement
2601 select. It is only allowed on sockets and pipes. */
2603 _sys_read_ahead (int fd
)
2608 if (fd
< 0 || fd
>= MAXDESC
)
2609 return STATUS_READ_ERROR
;
2611 cp
= fd_info
[fd
].cp
;
2613 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
2614 return STATUS_READ_ERROR
;
2616 if ((fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
)) == 0
2617 || (fd_info
[fd
].flags
& FILE_READ
) == 0)
2619 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe or socket!\n", fd
));
2623 cp
->status
= STATUS_READ_IN_PROGRESS
;
2625 if (fd_info
[fd
].flags
& FILE_PIPE
)
2627 rc
= _read (fd
, &cp
->chr
, sizeof (char));
2629 /* Give subprocess time to buffer some more output for us before
2630 reporting that input is available; we need this because Windows 95
2631 connects DOS programs to pipes by making the pipe appear to be
2632 the normal console stdout - as a result most DOS programs will
2633 write to stdout without buffering, ie. one character at a
2634 time. Even some W32 programs do this - "dir" in a command
2635 shell on NT is very slow if we don't do this. */
2638 int wait
= XINT (Vw32_pipe_read_delay
);
2644 /* Yield remainder of our time slice, effectively giving a
2645 temporary priority boost to the child process. */
2650 else if (fd_info
[fd
].flags
& FILE_SOCKET
)
2651 rc
= pfn_recv (SOCK_HANDLE (fd
), &cp
->chr
, sizeof (char), 0);
2654 if (rc
== sizeof (char))
2655 cp
->status
= STATUS_READ_SUCCEEDED
;
2657 cp
->status
= STATUS_READ_FAILED
;
2663 sys_read (int fd
, char * buffer
, unsigned int count
)
2668 char * orig_buffer
= buffer
;
2670 if (fd
< 0 || fd
>= MAXDESC
)
2676 if (fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
))
2678 child_process
*cp
= fd_info
[fd
].cp
;
2680 if ((fd_info
[fd
].flags
& FILE_READ
) == 0)
2688 /* re-read CR carried over from last read */
2689 if (fd_info
[fd
].flags
& FILE_LAST_CR
)
2691 if (fd_info
[fd
].flags
& FILE_BINARY
) abort ();
2695 fd_info
[fd
].flags
&= ~FILE_LAST_CR
;
2698 /* presence of a child_process structure means we are operating in
2699 non-blocking mode - otherwise we just call _read directly.
2700 Note that the child_process structure might be missing because
2701 reap_subprocess has been called; in this case the pipe is
2702 already broken, so calling _read on it is okay. */
2705 int current_status
= cp
->status
;
2707 switch (current_status
)
2709 case STATUS_READ_FAILED
:
2710 case STATUS_READ_ERROR
:
2711 /* report normal EOF if nothing in buffer */
2713 fd_info
[fd
].flags
|= FILE_AT_EOF
;
2716 case STATUS_READ_READY
:
2717 case STATUS_READ_IN_PROGRESS
:
2718 DebPrint (("sys_read called when read is in progress\n"));
2719 errno
= EWOULDBLOCK
;
2722 case STATUS_READ_SUCCEEDED
:
2723 /* consume read-ahead char */
2724 *buffer
++ = cp
->chr
;
2727 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
2728 ResetEvent (cp
->char_avail
);
2730 case STATUS_READ_ACKNOWLEDGED
:
2734 DebPrint (("sys_read: bad status %d\n", current_status
));
2739 if (fd_info
[fd
].flags
& FILE_PIPE
)
2741 PeekNamedPipe ((HANDLE
) _get_osfhandle (fd
), NULL
, 0, NULL
, &waiting
, NULL
);
2742 to_read
= min (waiting
, (DWORD
) count
);
2745 nchars
+= _read (fd
, buffer
, to_read
);
2748 else /* FILE_SOCKET */
2750 if (winsock_lib
== NULL
) abort ();
2752 /* do the equivalent of a non-blocking read */
2753 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONREAD
, &waiting
);
2754 if (waiting
== 0 && nchars
== 0)
2756 h_errno
= errno
= EWOULDBLOCK
;
2762 /* always use binary mode for sockets */
2763 int res
= pfn_recv (SOCK_HANDLE (fd
), buffer
, count
, 0);
2764 if (res
== SOCKET_ERROR
)
2766 DebPrint(("sys_read.recv failed with error %d on socket %ld\n",
2767 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
2778 int nread
= _read (fd
, buffer
, count
);
2781 else if (nchars
== 0)
2786 fd_info
[fd
].flags
|= FILE_AT_EOF
;
2787 /* Perform text mode translation if required. */
2788 else if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
2790 nchars
= crlf_to_lf (nchars
, orig_buffer
);
2791 /* If buffer contains only CR, return that. To be absolutely
2792 sure we should attempt to read the next char, but in
2793 practice a CR to be followed by LF would not appear by
2794 itself in the buffer. */
2795 if (nchars
> 1 && orig_buffer
[nchars
- 1] == 0x0d)
2797 fd_info
[fd
].flags
|= FILE_LAST_CR
;
2803 nchars
= _read (fd
, buffer
, count
);
2808 /* For now, don't bother with a non-blocking mode */
2810 sys_write (int fd
, const void * buffer
, unsigned int count
)
2814 if (fd
< 0 || fd
>= MAXDESC
)
2820 if (fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
))
2822 if ((fd_info
[fd
].flags
& FILE_WRITE
) == 0)
2828 /* Perform text mode translation if required. */
2829 if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
2831 char * tmpbuf
= alloca (count
* 2);
2832 unsigned char * src
= (void *)buffer
;
2833 unsigned char * dst
= tmpbuf
;
2838 unsigned char *next
;
2839 /* copy next line or remaining bytes */
2840 next
= _memccpy (dst
, src
, '\n', nbytes
);
2843 /* copied one line ending with '\n' */
2844 int copied
= next
- dst
;
2847 /* insert '\r' before '\n' */
2854 /* copied remaining partial line -> now finished */
2862 if (fd_info
[fd
].flags
& FILE_SOCKET
)
2864 if (winsock_lib
== NULL
) abort ();
2865 nchars
= pfn_send (SOCK_HANDLE (fd
), buffer
, count
, 0);
2866 if (nchars
== SOCKET_ERROR
)
2868 DebPrint(("sys_read.send failed with error %d on socket %ld\n",
2869 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
2875 nchars
= _write (fd
, buffer
, count
);
2881 check_windows_init_file ()
2883 extern int noninteractive
, inhibit_window_system
;
2885 /* A common indication that Emacs is not installed properly is when
2886 it cannot find the Windows installation file. If this file does
2887 not exist in the expected place, tell the user. */
2889 if (!noninteractive
&& !inhibit_window_system
) {
2890 extern Lisp_Object Vwindow_system
, Vload_path
;
2891 Lisp_Object init_file
;
2894 init_file
= build_string ("term/w32-win");
2895 fd
= openp (Vload_path
, init_file
, ".el:.elc", NULL
, 0);
2897 Lisp_Object load_path_print
= Fprin1_to_string (Vload_path
, Qnil
);
2898 char *init_file_name
= XSTRING (init_file
)->data
;
2899 char *load_path
= XSTRING (load_path_print
)->data
;
2900 char *buffer
= alloca (1024);
2903 "The Emacs Windows initialization file \"%s.el\" "
2904 "could not be found in your Emacs installation. "
2905 "Emacs checked the following directories for this file:\n"
2907 "When Emacs cannot find this file, it usually means that it "
2908 "was not installed properly, or its distribution file was "
2909 "not unpacked properly.\nSee the README.W32 file in the "
2910 "top-level Emacs directory for more information.",
2911 init_file_name
, load_path
);
2914 "Emacs Abort Dialog",
2915 MB_OK
| MB_ICONEXCLAMATION
| MB_TASKMODAL
);
2918 /* Use the low-level Emacs abort. */
2929 /* shutdown the socket interface if necessary */
2933 /* Check whether we are shutting down because we cannot find the
2934 Windows initialization file. Do this during shutdown so that
2935 Emacs is initialized as possible, and so that it is out of the
2936 critical startup path. */
2937 check_windows_init_file ();
2944 /* Initialise the socket interface now if available and requested by
2945 the user by defining PRELOAD_WINSOCK; otherwise loading will be
2946 delayed until open-network-stream is called (w32-has-winsock can
2947 also be used to dynamically load or reload winsock).
2949 Conveniently, init_environment is called before us, so
2950 PRELOAD_WINSOCK can be set in the registry. */
2952 /* Always initialize this correctly. */
2955 if (getenv ("PRELOAD_WINSOCK") != NULL
)
2956 init_winsock (TRUE
);
2959 /* Initial preparation for subprocess support: replace our standard
2960 handles with non-inheritable versions. */
2963 HANDLE stdin_save
= INVALID_HANDLE_VALUE
;
2964 HANDLE stdout_save
= INVALID_HANDLE_VALUE
;
2965 HANDLE stderr_save
= INVALID_HANDLE_VALUE
;
2967 parent
= GetCurrentProcess ();
2969 /* ignore errors when duplicating and closing; typically the
2970 handles will be invalid when running as a gui program. */
2971 DuplicateHandle (parent
,
2972 GetStdHandle (STD_INPUT_HANDLE
),
2977 DUPLICATE_SAME_ACCESS
);
2979 DuplicateHandle (parent
,
2980 GetStdHandle (STD_OUTPUT_HANDLE
),
2985 DUPLICATE_SAME_ACCESS
);
2987 DuplicateHandle (parent
,
2988 GetStdHandle (STD_ERROR_HANDLE
),
2993 DUPLICATE_SAME_ACCESS
);
2999 if (stdin_save
!= INVALID_HANDLE_VALUE
)
3000 _open_osfhandle ((long) stdin_save
, O_TEXT
);
3002 _open ("nul", O_TEXT
| O_NOINHERIT
| O_RDONLY
);
3005 if (stdout_save
!= INVALID_HANDLE_VALUE
)
3006 _open_osfhandle ((long) stdout_save
, O_TEXT
);
3008 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
3011 if (stderr_save
!= INVALID_HANDLE_VALUE
)
3012 _open_osfhandle ((long) stderr_save
, O_TEXT
);
3014 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
3018 /* unfortunately, atexit depends on implementation of malloc */
3019 /* atexit (term_ntproc); */
3020 signal (SIGABRT
, term_ntproc
);
3022 /* determine which drives are fixed, for GetCachedVolumeInformation */
3024 /* GetDriveType must have trailing backslash. */
3025 char drive
[] = "A:\\";
3027 /* Loop over all possible drive letters */
3028 while (*drive
<= 'Z')
3030 /* Record if this drive letter refers to a fixed drive. */
3031 fixed_drives
[DRIVE_INDEX (*drive
)] =
3032 (GetDriveType (drive
) == DRIVE_FIXED
);