1 /* Utility and Unix shadow routines for XEmacs on Windows NT.
2 Copyright (C) 1994, 1995 Free Software Foundation, Inc.
4 This file is part of XEmacs.
6 XEmacs is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 XEmacs is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 You should have received a copy of the GNU General Public License
17 along with XEmacs; see the file COPYING. If not, write to the Free
18 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
22 Geoff Voelker (voelker@cs.washington.edu) 7-29-94 */
24 /* Adapted for XEmacs by David Hobley <david@spook-le0.cia.com.au> */
25 /* Sync'ed with Emacs 19.34.6 by Marc Paquette <marcpa@cam.org> */
33 #include "syssignal.h"
39 #include "syswindows.h"
45 extern Lisp_Object Vmswindows_downcase_file_names;
47 extern Lisp_Object Vwin32_generate_fake_inodes;
49 extern Lisp_Object Vmswindows_get_true_file_attributes;
53 static char startup_dir[ MAXPATHLEN ];
55 /* Get the current working directory. */
60 if (GetCurrentDirectory (MAXPATHLEN, dir) > 0)
64 /* Emacs doesn't actually change directory itself, and we want to
65 force our real wd to be where emacs.exe is to avoid unnecessary
66 conflicts when trying to rename or delete directories. */
67 strcpy (dir, startup_dir);
72 /* Emulate getloadavg. */
74 getloadavg (double loadavg[], int nelem)
78 /* A faithful emulation is going to have to be saved for a rainy day. */
79 for (i = 0; i < nelem; i++)
86 /* Emulate getpwuid, getpwnam and others. */
88 #define PASSWD_FIELD_SIZE 256
90 static char the_passwd_name[PASSWD_FIELD_SIZE];
91 static char the_passwd_passwd[PASSWD_FIELD_SIZE];
92 static char the_passwd_gecos[PASSWD_FIELD_SIZE];
93 static char the_passwd_dir[PASSWD_FIELD_SIZE];
94 static char the_passwd_shell[PASSWD_FIELD_SIZE];
96 static struct passwd the_passwd =
111 return nt_fake_unix_uid;
117 return nt_fake_unix_uid;
123 return the_passwd.pw_gid;
135 if (uid == nt_fake_unix_uid)
137 the_passwd.pw_gid = the_passwd.pw_uid = uid;
145 getpwnam (const char *name)
149 pw = getpwuid (getuid ());
153 if (stricmp (name, pw->pw_name))
160 init_user_info (void)
162 /* This code is pretty much of ad hoc nature. There is no unix-like
163 UIDs under Windows NT. There is no concept of root user, because
164 all security is ACL-based. Instead, let's use a simple variable,
165 nt-fake-unix-uid, which would allow the user to have a uid of
166 choice. --kkm, 02/03/2000 */
168 /* Find the user's real name by opening the process token and
169 looking up the name associated with the user-sid in that token.
171 Use the relative portion of the identifier authority value from
172 the user-sid as the user id value (same for group id using the
173 primary group sid from the process token). */
175 char user_sid[256], name[256], domain[256];
176 DWORD length = sizeof (name), dlength = sizeof (domain), trash;
178 SID_NAME_USE user_type;
180 if (OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY, &token)
181 && GetTokenInformation (token, TokenUser,
182 (PVOID) user_sid, sizeof (user_sid), &trash)
183 && LookupAccountSid (NULL, *((PSID *) user_sid), name, &length,
184 domain, &dlength, &user_type))
186 strcpy (the_passwd.pw_name, name);
187 /* Determine a reasonable uid value. */
188 if (stricmp ("administrator", name) == 0)
190 the_passwd.pw_uid = 0;
191 the_passwd.pw_gid = 0;
195 SID_IDENTIFIER_AUTHORITY * pSIA;
197 pSIA = GetSidIdentifierAuthority (*((PSID *) user_sid));
198 /* I believe the relative portion is the last 4 bytes (of 6)
200 the_passwd.pw_uid = ((pSIA->Value[2] << 24) +
201 (pSIA->Value[3] << 16) +
202 (pSIA->Value[4] << 8) +
203 (pSIA->Value[5] << 0));
204 /* restrict to conventional uid range for normal users */
205 the_passwd.pw_uid = the_passwd.pw_uid % 60001;
208 if (GetTokenInformation (token, TokenPrimaryGroup,
209 (PVOID) user_sid, sizeof (user_sid), &trash))
211 SID_IDENTIFIER_AUTHORITY * pSIA;
213 pSIA = GetSidIdentifierAuthority (*((PSID *) user_sid));
214 the_passwd.pw_gid = ((pSIA->Value[2] << 24) +
215 (pSIA->Value[3] << 16) +
216 (pSIA->Value[4] << 8) +
217 (pSIA->Value[5] << 0));
218 /* I don't know if this is necessary, but for safety... */
219 the_passwd.pw_gid = the_passwd.pw_gid % 60001;
222 the_passwd.pw_gid = the_passwd.pw_uid;
225 /* If security calls are not supported (presumably because we
226 are running under Windows 95), fallback to this. */
227 else if (GetUserName (name, &length))
229 strcpy (the_passwd.pw_name, name);
230 if (stricmp ("administrator", name) == 0)
231 the_passwd.pw_uid = 0;
233 the_passwd.pw_uid = 123;
234 the_passwd.pw_gid = the_passwd.pw_uid;
238 strcpy (the_passwd.pw_name, "unknown");
239 the_passwd.pw_uid = 123;
240 the_passwd.pw_gid = 123;
246 /* Obtain only logon id here, uid part is moved to getuid */
248 DWORD length = sizeof (name);
249 if (GetUserName (name, &length))
250 strcpy (the_passwd.pw_name, name);
252 strcpy (the_passwd.pw_name, "unknown");
255 /* Ensure HOME and SHELL are defined. */
258 * With XEmacs, setting $HOME is deprecated.
260 if (getenv ("HOME") == NULL)
263 if (getenv ("SHELL") == NULL)
264 putenv ((GetVersion () & 0x80000000) ? "SHELL=command" : "SHELL=cmd");
266 /* Set dir and shell from environment variables. */
267 strcpy (the_passwd.pw_dir, (char *)get_home_directory());
268 strcpy (the_passwd.pw_shell, getenv ("SHELL"));
271 /* Normalize filename by converting all path separators to
272 the specified separator. Also conditionally convert upper
273 case path name components to lower case. */
276 normalize_filename (char *fp, char path_sep)
281 /* Always lower-case drive letters a-z, even if the filesystem
282 preserves case in filenames.
283 This is so filenames can be compared by string comparison
284 functions that are case-sensitive. Even case-preserving filesystems
285 do not distinguish case in drive letters. */
286 if (fp[1] == ':' && *fp >= 'A' && *fp <= 'Z')
292 if (NILP (Vmswindows_downcase_file_names))
296 if (*fp == '/' || *fp == '\\')
303 sep = path_sep; /* convert to this path separator */
304 elem = fp; /* start of current path element */
307 if (*fp >= 'a' && *fp <= 'z')
308 elem = 0; /* don't convert this element */
310 if (*fp == 0 || *fp == ':')
312 sep = *fp; /* restore current separator (or 0) */
313 *fp = '/'; /* after conversion of this element */
316 if (*fp == '/' || *fp == '\\')
318 if (elem && elem != fp)
320 *fp = 0; /* temporary end of string */
321 _strlwr (elem); /* while we convert to lower case */
323 *fp = sep; /* convert (or restore) path separator */
324 elem = fp + 1; /* next element starts after separator */
330 /* Destructively turn backslashes into slashes. */
332 dostounix_filename (char *p)
334 normalize_filename (p, '/');
337 /* Destructively turn slashes into backslashes. */
339 unixtodos_filename (char *p)
341 normalize_filename (p, '\\');
344 /* Remove all CR's that are followed by a LF.
345 (From msdos.c...probably should figure out a way to share it,
346 although this code isn't going to ever change.) */
348 crlf_to_lf (int n, unsigned char *buf, unsigned *lf_count)
350 unsigned char *np = buf;
351 unsigned char *startp = buf;
352 unsigned char *endp = buf + n;
356 while (buf < endp - 1)
362 if (*(++buf) != 0x0a)
377 /* Parse the root part of file name, if present. Return length and
378 optionally store pointer to char after root. */
380 parse_root (char * name, char ** pPath)
387 /* find the root name of the volume if given */
388 if (isalpha (name[0]) && name[1] == ':')
390 /* skip past drive specifier */
392 if (IS_DIRECTORY_SEP (name[0]))
395 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
401 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
406 if (IS_DIRECTORY_SEP (name[0]))
416 /* Get long base name for name; name is assumed to be absolute. */
418 get_long_basename (char * name, char * buf, int size)
420 WIN32_FIND_DATA find_data;
426 /* If the last component of NAME has a wildcard character,
427 return it as the basename. */
428 p = name + strlen (name);
429 while (*p != '\\' && *p != ':' && p > name) p--;
431 if (strchr (p, '*') || strchr (p, '?'))
433 if ((len = strlen (p)) < size)
434 memcpy (buf, p, len + 1);
441 dir_handle = FindFirstFile (name, &find_data);
442 if (dir_handle != INVALID_HANDLE_VALUE)
444 if ((len = strlen (find_data.cFileName)) < size)
445 memcpy (buf, find_data.cFileName, len + 1);
448 FindClose (dir_handle);
453 /* Get long name for file, if possible (assumed to be absolute). */
455 win32_get_long_filename (char * name, char * buf, int size)
460 char full[ MAX_PATH ];
467 /* Use local copy for destructive modification. */
468 memcpy (full, name, len+1);
469 unixtodos_filename (full);
471 /* Copy root part verbatim. */
472 len = parse_root (full, &p);
473 memcpy (o, full, len);
480 p = strchr (q, '\\');
482 len = get_long_basename (full, o, size);
500 while (p != NULL && *p);
506 /* Routines that are no-ops on NT but are defined to get Emacs to compile. */
508 #if 0 /* #### We do not need those, do we? -kkm */
510 unrequest_sigio (void)
522 #define REG_ROOT "SOFTWARE\\GNU\\XEmacs"
525 nt_get_resource (char *key, LPDWORD lpdwtype)
528 HKEY hrootkey = NULL;
531 /* Check both the current user and the local machine to see if
532 we have any resources. */
534 if (RegOpenKeyEx (HKEY_CURRENT_USER, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
538 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
539 && (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL
540 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
545 if (lpvalue) xfree (lpvalue);
547 RegCloseKey (hrootkey);
550 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
554 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS &&
555 (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL &&
556 RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
561 if (lpvalue) xfree (lpvalue);
563 RegCloseKey (hrootkey);
570 init_environment (void)
572 /* Check for environment variables and use registry if they don't exist */
578 static char * env_vars[] =
592 #if defined (HEAP_IN_DATA) && !defined(PDUMP)
593 cache_system_info ();
595 for (i = 0; i < countof (env_vars); i++)
597 if (!getenv (env_vars[i]) &&
598 (lpval = nt_get_resource (env_vars[i], &dwType)) != NULL)
600 if (dwType == REG_EXPAND_SZ)
602 char buf1[500], buf2[500];
604 ExpandEnvironmentStrings ((LPSTR) lpval, buf1, 500);
605 _snprintf (buf2, 499, "%s=%s", env_vars[i], buf1);
606 putenv (strdup (buf2));
608 else if (dwType == REG_SZ)
612 _snprintf (buf, 499, "%s=%s", env_vars[i], lpval);
613 putenv (strdup (buf));
621 /* Another special case: on NT, the PATH variable is actually named
622 "Path" although cmd.exe (perhaps NT itself) arranges for
623 environment variable lookup and setting to be case insensitive.
624 However, Emacs assumes a fully case sensitive environment, so we
625 need to change "Path" to "PATH" to match the expectations of
626 various elisp packages. We do this by the sneaky method of
627 modifying the string in the C runtime environ entry.
629 The same applies to COMSPEC. */
633 for (envp = environ; *envp; envp++)
634 if (_strnicmp (*envp, "PATH=", 5) == 0)
635 memcpy (*envp, "PATH=", 5);
636 else if (_strnicmp (*envp, "COMSPEC=", 8) == 0)
637 memcpy (*envp, "COMSPEC=", 8);
640 /* Remember the initial working directory for getwd, then make the
641 real wd be the location of emacs.exe to avoid conflicts when
642 renaming or deleting directories. (We also don't call chdir when
643 running subprocesses for the same reason.) */
644 if (!GetCurrentDirectory (MAXPATHLEN, startup_dir))
649 char modname[MAX_PATH];
651 if (!GetModuleFileName (NULL, modname, MAX_PATH))
653 if ((p = strrchr (modname, '\\')) == NULL)
657 SetCurrentDirectory (modname);
663 #ifndef HAVE_X_WINDOWS
664 /* X11R6 on NT provides the single parameter version of this command. */
666 #include <sys/timeb.h>
668 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
670 gettimeofday (struct timeval *tv, struct timezone *tz)
675 tv->tv_sec = tb.time;
676 tv->tv_usec = tb.millitm * 1000L;
679 tz->tz_minuteswest = tb.timezone; /* minutes west of Greenwich */
680 tz->tz_dsttime = tb.dstflag; /* type of dst correction */
684 #endif /* HAVE_X_WINDOWS */
686 /* ------------------------------------------------------------------------- */
687 /* IO support and wrapper functions for Win32 API. */
688 /* ------------------------------------------------------------------------- */
690 /* Place a wrapper around the MSVC version of ctime. It returns NULL
691 on network directories, so we handle that case here.
692 (Ulrich Leodolter, 1/11/95). */
694 sys_ctime (const time_t *t)
696 char *str = (char *) ctime (t);
697 return (str ? str : "Sun Jan 01 00:00:00 1970");
700 /* Emulate sleep...we could have done this with a define, but that
701 would necessitate including windows.h in the files that used it.
702 This is much easier. */
704 #ifndef HAVE_X_WINDOWS
706 sys_sleep (int seconds)
708 Sleep (seconds * 1000);
712 /* #### This is an evil dirty hack. We must get rid of it.
713 Word "munging" is not in XEmacs lexicon. - kkm */
715 /* Internal MSVC data and functions for low-level descriptor munging */
716 #if (_MSC_VER == 900)
717 extern char _osfile[];
719 extern int __cdecl _set_osfhnd (int fd, long h);
720 extern int __cdecl _free_osfhnd (int fd);
722 /* parallel array of private info on file handles */
723 filedesc fd_info [ MAXDESC ];
725 typedef struct volume_info_data {
726 struct volume_info_data * next;
728 /* time when info was obtained */
731 /* actual volume info */
740 /* Global referenced by various functions. */
741 static volume_info_data volume_info;
743 /* Vector to indicate which drives are local and fixed (for which cached
744 data never expires). */
745 static BOOL fixed_drives[26];
747 /* Consider cached volume information to be stale if older than 10s,
748 at least for non-local drives. Info for fixed drives is never stale. */
749 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
750 #define VOLINFO_STILL_VALID( root_dir, info ) \
751 ( ( isalpha (root_dir[0]) && \
752 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
753 || GetTickCount () - info->timestamp < 10000 )
755 /* Cache support functions. */
757 /* Simple linked list with linear search is sufficient. */
758 static volume_info_data *volume_cache = NULL;
760 static volume_info_data *
761 lookup_volume_info (char * root_dir)
763 volume_info_data * info;
765 for (info = volume_cache; info; info = info->next)
766 if (stricmp (info->root_dir, root_dir) == 0)
772 add_volume_info (char * root_dir, volume_info_data * info)
774 info->root_dir = xstrdup (root_dir);
775 info->next = volume_cache;
780 /* Wrapper for GetVolumeInformation, which uses caching to avoid
781 performance penalty (~2ms on 486 for local drives, 7.5ms for local
782 cdrom drive, ~5-10ms or more for remote drives on LAN). */
784 GetCachedVolumeInformation (char * root_dir)
786 volume_info_data * info;
787 char default_root[ MAX_PATH ];
789 /* NULL for root_dir means use root from current directory. */
790 if (root_dir == NULL)
792 if (GetCurrentDirectory (MAX_PATH, default_root) == 0)
794 parse_root (default_root, &root_dir);
796 root_dir = default_root;
799 /* Local fixed drives can be cached permanently. Removable drives
800 cannot be cached permanently, since the volume name and serial
801 number (if nothing else) can change. Remote drives should be
802 treated as if they are removable, since there is no sure way to
803 tell whether they are or not. Also, the UNC association of drive
804 letters mapped to remote volumes can be changed at any time (even
805 by other processes) without notice.
807 As a compromise, so we can benefit from caching info for remote
808 volumes, we use a simple expiry mechanism to invalidate cache
809 entries that are more than ten seconds old. */
812 /* No point doing this, because WNetGetConnection is even slower than
813 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
814 GetDriveType is about the only call of this type which does not
815 involve network access, and so is extremely quick). */
817 /* Map drive letter to UNC if remote. */
818 if ( isalpha( root_dir[0] ) && !fixed[ DRIVE_INDEX( root_dir[0] ) ] )
820 char remote_name[ 256 ];
821 char drive[3] = { root_dir[0], ':' };
823 if (WNetGetConnection (drive, remote_name, sizeof (remote_name))
829 info = lookup_volume_info (root_dir);
831 if (info == NULL || ! VOLINFO_STILL_VALID (root_dir, info))
839 /* Info is not cached, or is stale. */
840 if (!GetVolumeInformation (root_dir,
845 type, sizeof (type)))
848 /* Cache the volume information for future use, overwriting existing
852 info = (volume_info_data *) xmalloc (sizeof (volume_info_data));
853 add_volume_info (root_dir, info);
861 info->name = xstrdup (name);
862 info->serialnum = serialnum;
863 info->maxcomp = maxcomp;
865 info->type = xstrdup (type);
866 info->timestamp = GetTickCount ();
872 /* Get information on the volume where name is held; set path pointer to
873 start of pathname in name (past UNC header\volume header if present). */
875 get_volume_info (const char * name, const char ** pPath)
878 char *rootname = NULL; /* default to current volume */
879 volume_info_data * info;
884 /* find the root name of the volume if given */
885 if (isalpha (name[0]) && name[1] == ':')
893 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
900 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
913 info = GetCachedVolumeInformation (rootname);
916 /* Set global referenced by other functions. */
923 /* Determine if volume is FAT format (ie. only supports short 8.3
924 names); also set path pointer to start of pathname in name. */
926 is_fat_volume (const char * name, const char ** pPath)
928 if (get_volume_info (name, pPath))
929 return (volume_info.maxcomp == 12);
933 /* Map filename to a legal 8.3 name if necessary. */
935 map_win32_filename (const char * name, const char ** pPath)
937 static char shortname[MAX_PATH];
938 char * str = shortname;
941 const char * save_name = name;
943 if (is_fat_volume (name, &path)) /* truncate to 8.3 */
945 REGISTER int left = 8; /* maximum number of chars in part */
946 REGISTER int extn = 0; /* extension added? */
947 REGISTER int dots = 2; /* maximum number of dots allowed */
950 *str++ = *name++; /* skip past UNC header */
952 while ((c = *name++))
959 extn = 0; /* reset extension flags */
960 dots = 2; /* max 2 dots */
961 left = 8; /* max length 8 for main part */
965 extn = 0; /* reset extension flags */
966 dots = 2; /* max 2 dots */
967 left = 8; /* max length 8 for main part */
972 /* Convert path components of the form .xxx to _xxx,
973 but leave . and .. as they are. This allows .emacs
974 to be read as _emacs, for example. */
978 IS_DIRECTORY_SEP (*name))
993 extn = 1; /* we've got an extension */
994 left = 3; /* 3 chars in extension */
998 /* any embedded dots after the first are converted to _ */
1003 case '#': /* don't lose these, they're important */
1005 str[-1] = c; /* replace last character of part */
1010 *str++ = tolower (c); /* map to lower case (looks nicer) */
1012 dots = 0; /* started a path component */
1021 strcpy (shortname, name);
1022 unixtodos_filename (shortname);
1026 *pPath = shortname + (path - save_name);
1032 /* Emulate the Unix directory procedures opendir, closedir,
1033 and readdir. We can't use the procedures supplied in sysdep.c,
1034 so we provide them here. */
1036 struct direct dir_static; /* simulated directory contents */
1037 static HANDLE dir_find_handle = INVALID_HANDLE_VALUE;
1038 static int dir_is_fat;
1039 static char dir_pathname[MAXPATHLEN+1];
1040 static WIN32_FIND_DATA dir_find_data;
1043 opendir (const char *filename)
1047 /* Opening is done by FindFirstFile. However, a read is inherent to
1048 this operation, so we defer the open until read time. */
1050 if (!(dirp = xnew_and_zero(DIR)))
1052 if (dir_find_handle != INVALID_HANDLE_VALUE)
1059 strncpy (dir_pathname, map_win32_filename (filename, NULL), MAXPATHLEN);
1060 dir_pathname[MAXPATHLEN] = '\0';
1061 dir_is_fat = is_fat_volume (filename, NULL);
1067 closedir (DIR *dirp)
1071 /* If we have a find-handle open, close it. */
1072 if (dir_find_handle != INVALID_HANDLE_VALUE)
1074 retval = FindClose (dir_find_handle);
1075 dir_find_handle = INVALID_HANDLE_VALUE;
1087 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
1088 if (dir_find_handle == INVALID_HANDLE_VALUE)
1090 char filename[MAXNAMLEN + 3];
1093 strcpy (filename, dir_pathname);
1094 ln = strlen (filename) - 1;
1095 if (!IS_DIRECTORY_SEP (filename[ln]))
1096 strcat (filename, "\\");
1097 strcat (filename, "*");
1099 dir_find_handle = FindFirstFile (filename, &dir_find_data);
1101 if (dir_find_handle == INVALID_HANDLE_VALUE)
1106 if (!FindNextFile (dir_find_handle, &dir_find_data))
1110 /* Emacs never uses this value, so don't bother making it match
1111 value returned by stat(). */
1112 dir_static.d_ino = 1;
1114 dir_static.d_reclen = sizeof (struct direct) - MAXNAMLEN + 3 +
1115 dir_static.d_namlen - dir_static.d_namlen % 4;
1117 dir_static.d_namlen = strlen (dir_find_data.cFileName);
1118 strcpy (dir_static.d_name, dir_find_data.cFileName);
1120 _strlwr (dir_static.d_name);
1121 else if (!NILP (Vmswindows_downcase_file_names))
1124 for (p = dir_static.d_name; *p; p++)
1125 if (*p >= 'a' && *p <= 'z')
1128 _strlwr (dir_static.d_name);
1135 /* #### Have to check if all that sad story about '95 is true - kkm */
1137 sys_rename (const char * oldname, const char * newname)
1139 char temp[MAX_PATH];
1142 /* MoveFile on Win95 doesn't correctly change the short file name
1143 alias in a number of circumstances (it is not easy to predict when
1144 just by looking at oldname and newname, unfortunately). In these
1145 cases, renaming through a temporary name avoids the problem.
1147 A second problem on Win95 is that renaming through a temp name when
1148 newname is uppercase fails (the final long name ends up in
1149 lowercase, although the short alias might be uppercase) UNLESS the
1150 long temp name is not 8.3.
1152 So, on Win95 we always rename through a temp name, and we make sure
1153 the temp name has a long extension to ensure correct renaming. */
1155 strcpy (temp, map_win32_filename (oldname, NULL));
1157 if (GetVersion () & 0x80000000)
1161 if (p = strrchr (temp, '\\'))
1165 /* Force temp name to require a manufactured 8.3 alias - this
1166 seems to make the second rename work properly. */
1167 strcpy (p, "_rename_temp.XXXXXX");
1169 if (rename (map_win32_filename (oldname, NULL), temp) < 0)
1173 /* Emulate Unix behavior - newname is deleted if it already exists
1174 (at least if it is a file; don't do this for directories).
1175 However, don't do this if we are just changing the case of the file
1176 name - we will end up deleting the file we are trying to rename! */
1177 newname = map_win32_filename (newname, NULL);
1179 /* TODO: Use GetInformationByHandle (on NT) to ensure newname and temp
1180 do not refer to the same file, eg. through share aliases. */
1181 if (stricmp (newname, temp) != 0
1182 && (attr = GetFileAttributes (newname)) != -1
1183 && (attr & FILE_ATTRIBUTE_DIRECTORY) == 0)
1185 _chmod (newname, 0666);
1189 return rename (temp, newname);
1193 static FILETIME utc_base_ft;
1194 static int init = 0;
1198 static long double utc_base;
1201 convert_time (FILETIME ft)
1207 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
1216 st.wMilliseconds = 0;
1218 SystemTimeToFileTime (&st, &utc_base_ft);
1219 utc_base = (long double) utc_base_ft.dwHighDateTime
1220 * 4096 * 1024 * 1024 + utc_base_ft.dwLowDateTime;
1224 if (CompareFileTime (&ft, &utc_base_ft) < 0)
1227 ret = (long double) ft.dwHighDateTime * 4096 * 1024 * 1024 + ft.dwLowDateTime;
1229 return (time_t) (ret * 1e-7);
1233 #if defined(MINGW) && CYGWIN_VERSION_DLL_MAJOR <= 21
1234 #define LowPart u.LowPart
1235 #define HighPart u.HighPart
1238 static LARGE_INTEGER utc_base_li;
1241 convert_time (FILETIME uft)
1248 TIME_ZONE_INFORMATION tzi;
1256 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
1265 st.wMilliseconds = 0;
1267 SystemTimeToFileTime (&st, &utc_base_ft);
1269 utc_base_li.LowPart = utc_base_ft.dwLowDateTime;
1270 utc_base_li.HighPart = utc_base_ft.dwHighDateTime;
1277 /* On a compiler that supports long integers, do it the easy way */
1278 lft.LowPart = uft.dwLowDateTime;
1279 lft.HighPart = uft.dwHighDateTime;
1280 ret = (time_t) ((lft.QuadPart - utc_base_li.QuadPart) / 10000000);
1284 /* Do it the hard way using mktime. */
1285 FileTimeToLocalFileTime(&uft, &ft);
1286 FileTimeToSystemTime (&ft, &st);
1287 tzid = GetTimeZoneInformation (&tzi);
1288 t.tm_year = st.wYear - 1900;
1289 t.tm_mon = st.wMonth - 1;
1290 t.tm_mday = st.wDay;
1291 t.tm_hour = st.wHour;
1292 t.tm_min = st.wMinute;
1293 t.tm_sec = st.wSecond;
1294 t.tm_isdst = (tzid == TIME_ZONE_ID_DAYLIGHT);
1295 /* st.wMilliseconds not applicable */
1307 #if defined(MINGW) && CYGWIN_VERSION_DLL_MAJOR <= 21
1313 /* in case we ever have need of this */
1315 convert_from_time_t (time_t time, FILETIME * pft)
1321 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
1330 st.wMilliseconds = 0;
1332 SystemTimeToFileTime (&st, &utc_base_ft);
1333 utc_base = (long double) utc_base_ft.dwHighDateTime
1334 * 4096 * 1024 * 1024 + utc_base_ft.dwLowDateTime;
1338 /* time in 100ns units since 1-Jan-1601 */
1339 tmp = (long double) time * 1e7 + utc_base;
1340 pft->dwHighDateTime = (DWORD) (tmp / (4096.0 * 1024 * 1024));
1341 pft->dwLowDateTime = (DWORD) (tmp - pft->dwHighDateTime);
1346 /* No reason to keep this; faking inode values either by hashing or even
1347 using the file index from GetInformationByHandle, is not perfect and
1348 so by default Emacs doesn't use the inode values on Windows.
1349 Instead, we now determine file-truename correctly (except for
1350 possible drive aliasing etc). */
1352 /* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
1354 hashval (const unsigned char * str)
1359 h = (h << 4) + *str++;
1365 /* Return the hash value of the canonical pathname, excluding the
1366 drive/UNC header, to get a hopefully unique inode number. */
1368 generate_inode_val (const char * name)
1370 char fullname[ MAX_PATH ];
1374 /* Get the truly canonical filename, if it exists. (Note: this
1375 doesn't resolve aliasing due to subst commands, or recognize hard
1377 if (!win32_get_long_filename ((char *)name, fullname, MAX_PATH))
1380 parse_root (fullname, &p);
1381 /* Normal Win32 filesystems are still case insensitive. */
1388 /* #### aichner@ecf.teradyne.com reported that with the library
1389 provided stat/fstat, (file-exist "d:\\tmp\\") =>> nil,
1390 (file-exist "d:\\tmp") =>> t, when d:\tmp exists. Whenever
1391 we opt to use non-encapsulated stat(), this should serve as
1392 a compatibility test. --kkm */
1394 /* Since stat is encapsulated on Windows NT, we need to encapsulate
1395 the equally broken fstat as well. */
1397 mswindows_fstat (int handle, struct stat *buffer)
1400 BY_HANDLE_FILE_INFORMATION lpFileInfo;
1401 /* Initialize values */
1402 buffer->st_mode = 0;
1403 buffer->st_size = 0;
1405 buffer->st_rdev = 0;
1406 buffer->st_atime = 0;
1407 buffer->st_ctime = 0;
1408 buffer->st_mtime = 0;
1409 buffer->st_nlink = 0;
1410 ret = GetFileInformationByHandle((HANDLE) _get_osfhandle(handle), &lpFileInfo);
1417 buffer->st_mtime = convert_time (lpFileInfo.ftLastWriteTime);
1418 buffer->st_atime = convert_time (lpFileInfo.ftLastAccessTime);
1419 if (buffer->st_atime == 0) buffer->st_atime = buffer->st_mtime;
1420 buffer->st_ctime = convert_time (lpFileInfo.ftCreationTime);
1421 if (buffer->st_ctime == 0) buffer->st_ctime = buffer->st_mtime;
1422 buffer->st_size = lpFileInfo.nFileSizeLow;
1423 buffer->st_nlink = (short) lpFileInfo.nNumberOfLinks;
1428 /* MSVC stat function can't cope with UNC names and has other bugs, so
1429 replace it with our own. This also allows us to calculate consistent
1430 inode values without hacks in the main Emacs code. */
1432 mswindows_stat (const char * path, struct stat * buf)
1435 WIN32_FIND_DATA wfd;
1440 int rootdir = FALSE;
1442 if (path == NULL || buf == NULL)
1448 name = (char *) map_win32_filename (path, &path);
1449 /* must be valid filename, no wild cards */
1450 if (strchr (name, '*') || strchr (name, '?'))
1456 /* Remove trailing directory separator, unless name is the root
1457 directory of a drive or UNC volume in which case ensure there
1458 is a trailing separator. */
1459 len = strlen (name);
1460 rootdir = (path >= name + len - 1
1461 && (IS_DIRECTORY_SEP (*path) || *path == 0));
1462 name = strcpy ((char *)alloca (len + 2), name);
1466 if (!IS_DIRECTORY_SEP (name[len-1]))
1467 strcat (name, "\\");
1468 if (GetDriveType (name) < 2)
1473 memset (&wfd, 0, sizeof (wfd));
1474 wfd.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
1475 wfd.ftCreationTime = utc_base_ft;
1476 wfd.ftLastAccessTime = utc_base_ft;
1477 wfd.ftLastWriteTime = utc_base_ft;
1478 strcpy (wfd.cFileName, name);
1482 if (IS_DIRECTORY_SEP (name[len-1]))
1485 /* (This is hacky, but helps when doing file completions on
1486 network drives.) Optimize by using information available from
1487 active readdir if possible. */
1488 if (dir_find_handle != INVALID_HANDLE_VALUE &&
1489 (len = strlen (dir_pathname)),
1490 strnicmp (name, dir_pathname, len) == 0 &&
1491 IS_DIRECTORY_SEP (name[len]) &&
1492 stricmp (name + len + 1, dir_static.d_name) == 0)
1494 /* This was the last entry returned by readdir. */
1495 wfd = dir_find_data;
1499 fh = FindFirstFile (name, &wfd);
1500 if (fh == INVALID_HANDLE_VALUE)
1509 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1511 buf->st_mode = _S_IFDIR;
1512 buf->st_nlink = 2; /* doesn't really matter */
1513 fake_inode = 0; /* this doesn't either I think */
1515 else if (!NILP (Vmswindows_get_true_file_attributes))
1517 /* This is more accurate in terms of getting the correct number
1518 of links, but is quite slow (it is noticeable when Emacs is
1519 making a list of file name completions). */
1520 BY_HANDLE_FILE_INFORMATION info;
1522 /* No access rights required to get info. */
1523 fh = CreateFile (name, 0, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
1524 OPEN_EXISTING, 0, NULL);
1526 if (GetFileInformationByHandle (fh, &info))
1528 switch (GetFileType (fh))
1530 case FILE_TYPE_DISK:
1531 buf->st_mode = _S_IFREG;
1533 case FILE_TYPE_PIPE:
1534 buf->st_mode = _S_IFIFO;
1536 case FILE_TYPE_CHAR:
1537 case FILE_TYPE_UNKNOWN:
1539 buf->st_mode = _S_IFCHR;
1541 buf->st_nlink = (short) info.nNumberOfLinks;
1542 /* Might as well use file index to fake inode values, but this
1543 is not guaranteed to be unique unless we keep a handle open
1544 all the time (even then there are situations where it is
1545 not unique). Reputedly, there are at most 48 bits of info
1546 (on NTFS, presumably less on FAT). */
1547 fake_inode = info.nFileIndexLow ^ info.nFileIndexHigh;
1558 /* Don't bother to make this information more accurate. */
1559 buf->st_mode = _S_IFREG;
1565 /* Not sure if there is any point in this. */
1566 if (!NILP (Vwin32_generate_fake_inodes))
1567 fake_inode = generate_inode_val (name);
1568 else if (fake_inode == 0)
1570 /* For want of something better, try to make everything unique. */
1571 static DWORD gen_num = 0;
1572 fake_inode = ++gen_num;
1576 /* #### MSVC defines _ino_t to be short; other libc's might not. */
1577 buf->st_ino = (unsigned short) (fake_inode ^ (fake_inode >> 16));
1579 /* consider files to belong to current user */
1580 buf->st_uid = buf->st_gid = nt_fake_unix_uid;
1582 /* volume_info is set indirectly by map_win32_filename */
1583 buf->st_dev = volume_info.serialnum;
1584 buf->st_rdev = volume_info.serialnum;
1586 buf->st_size = wfd.nFileSizeLow;
1588 /* Convert timestamps to Unix format. */
1589 buf->st_mtime = convert_time (wfd.ftLastWriteTime);
1590 buf->st_atime = convert_time (wfd.ftLastAccessTime);
1591 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
1592 buf->st_ctime = convert_time (wfd.ftCreationTime);
1593 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
1595 /* determine rwx permissions */
1596 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
1597 permission = _S_IREAD;
1599 permission = _S_IREAD | _S_IWRITE;
1601 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1602 permission |= _S_IEXEC;
1605 char * p = strrchr (name, '.');
1607 (stricmp (p, ".exe") == 0 ||
1608 stricmp (p, ".com") == 0 ||
1609 stricmp (p, ".bat") == 0 ||
1610 stricmp (p, ".cmd") == 0))
1611 permission |= _S_IEXEC;
1614 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
1619 /* From callproc.c */
1620 extern Lisp_Object Vbinary_process_input;
1621 extern Lisp_Object Vbinary_process_output;
1623 /* Unix pipe() has only one arg */
1625 sys_pipe (int * phandles)
1630 /* make pipe handles non-inheritable; when we spawn a child, we
1631 replace the relevant handle with an inheritable one. Also put
1632 pipes into binary mode; we will do text mode translation ourselves
1634 rc = _pipe (phandles, 0, _O_NOINHERIT | _O_BINARY);
1638 flags = FILE_PIPE | FILE_READ;
1639 if (!NILP (Vbinary_process_output))
1640 flags |= FILE_BINARY;
1641 fd_info[phandles[0]].flags = flags;
1643 flags = FILE_PIPE | FILE_WRITE;
1644 if (!NILP (Vbinary_process_input))
1645 flags |= FILE_BINARY;
1646 fd_info[phandles[1]].flags = flags;
1653 term_ntproc (int unused)
1660 /* Initial preparation for subprocess support: replace our standard
1661 handles with non-inheritable versions. */
1664 HANDLE stdin_save = INVALID_HANDLE_VALUE;
1665 HANDLE stdout_save = INVALID_HANDLE_VALUE;
1666 HANDLE stderr_save = INVALID_HANDLE_VALUE;
1668 parent = GetCurrentProcess ();
1670 /* ignore errors when duplicating and closing; typically the
1671 handles will be invalid when running as a gui program. */
1672 DuplicateHandle (parent,
1673 GetStdHandle (STD_INPUT_HANDLE),
1678 DUPLICATE_SAME_ACCESS);
1680 DuplicateHandle (parent,
1681 GetStdHandle (STD_OUTPUT_HANDLE),
1686 DUPLICATE_SAME_ACCESS);
1688 DuplicateHandle (parent,
1689 GetStdHandle (STD_ERROR_HANDLE),
1694 DUPLICATE_SAME_ACCESS);
1700 if (stdin_save != INVALID_HANDLE_VALUE)
1701 _open_osfhandle ((long) stdin_save, O_TEXT);
1703 _open ("nul", O_TEXT | O_NOINHERIT | O_RDONLY);
1706 if (stdout_save != INVALID_HANDLE_VALUE)
1707 _open_osfhandle ((long) stdout_save, O_TEXT);
1709 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
1712 if (stderr_save != INVALID_HANDLE_VALUE)
1713 _open_osfhandle ((long) stderr_save, O_TEXT);
1715 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
1719 /* unfortunately, atexit depends on implementation of malloc */
1720 /* atexit (term_ntproc); */
1721 signal (SIGABRT, term_ntproc);
1723 /* determine which drives are fixed, for GetCachedVolumeInformation */
1725 /* GetDriveType must have trailing backslash. */
1726 char drive[] = "A:\\";
1728 /* Loop over all possible drive letters */
1729 while ( *drive <= 'Z' )
1731 /* Record if this drive letter refers to a fixed drive. */
1732 fixed_drives[ DRIVE_INDEX (*drive) ] =
1733 (GetDriveType (drive) == DRIVE_FIXED);
1741 tty_semi_canonicalize_console_connection (Lisp_Object connection,
1742 Error_behavior errb)
1748 tty_canonicalize_console_connection (Lisp_Object connection,
1749 Error_behavior errb)
1755 tty_semi_canonicalize_device_connection (Lisp_Object connection,
1756 Error_behavior errb)
1762 tty_canonicalize_device_connection (Lisp_Object connection,
1763 Error_behavior errb)
1769 /*--------------------------------------------------------------------*/
1770 /* Signal support */
1771 /*--------------------------------------------------------------------*/
1773 /* We need MS-defined signal and raise here */
1777 #define sigmask(nsig) (1U << nsig)
1779 /* We can support as many signals as fit into word */
1782 /* Signal handlers. Initial value = 0 = SIG_DFL */
1783 static void (__cdecl *signal_handlers[SIG_MAX])(int) = {0};
1785 /* Signal block mask: bit set to 1 means blocked */
1786 unsigned signal_block_mask = 0;
1788 /* Signal pending mask: bit set to 1 means sig is pending */
1789 unsigned signal_pending_mask = 0;
1791 mswindows_sighandler mswindows_sigset (int nsig, mswindows_sighandler handler)
1793 /* We delegate some signals to the system function */
1794 if (nsig == SIGFPE || nsig == SIGABRT || nsig == SIGINT)
1795 return signal (nsig, handler);
1797 if (nsig < 0 || nsig > SIG_MAX)
1803 /* Store handler ptr */
1805 mswindows_sighandler old_handler = signal_handlers[nsig];
1806 signal_handlers[nsig] = handler;
1811 int mswindows_sighold (int nsig)
1813 if (nsig < 0 || nsig > SIG_MAX)
1814 return errno = EINVAL;
1816 signal_block_mask |= sigmask(nsig);
1820 int mswindows_sigrelse (int nsig)
1822 if (nsig < 0 || nsig > SIG_MAX)
1823 return errno = EINVAL;
1825 signal_block_mask &= ~sigmask(nsig);
1827 if (signal_pending_mask & sigmask(nsig))
1828 mswindows_raise (nsig);
1833 int mswindows_sigpause (int nsig)
1835 /* This is currently not called, because the only
1836 call to sigpause inside XEmacs is with SIGCHLD
1837 parameter. Just in case, we put an assert here,
1838 so anyone who will add a call to sigpause will
1839 be surprised (or surprise someone else...) */
1844 int mswindows_raise (int nsig)
1846 /* We delegate some raises to the system routine */
1847 if (nsig == SIGFPE || nsig == SIGABRT || nsig == SIGINT)
1848 return raise (nsig);
1850 if (nsig < 0 || nsig > SIG_MAX)
1851 return errno = EINVAL;
1853 /* If the signal is blocked, remember to issue later */
1854 if (signal_block_mask & sigmask(nsig))
1856 signal_pending_mask |= sigmask(nsig);
1860 if (signal_handlers[nsig] == SIG_IGN)
1863 if (signal_handlers[nsig] != SIG_DFL)
1865 (*signal_handlers[nsig])(nsig);
1869 /* Default signal actions */
1870 if (nsig == SIGALRM || nsig == SIGPROF)
1873 /* Other signals are ignored by default */
1877 /*--------------------------------------------------------------------*/
1879 /*--------------------------------------------------------------------*/
1881 /* We emulate two timers, one for SIGALRM, another for SIGPROF.
1883 itimerproc() function has an implementation limitation: it does
1884 not allow to set *both* interval and period. If an attempt is
1885 made to set both, and then they are unequal, the function
1888 Minimum timer resolution on Win32 systems varies, and is greater
1889 than or equal than 1 ms. The resolution is always wrapped not to
1890 attempt to get below the system defined limit.
1893 /* Timer precision, denominator of one fraction: for 100 ms
1894 interval, request 10 ms precision
1896 const int timer_prec = 10;
1898 /* Last itimervals, as set by calls to setitimer */
1899 static struct itimerval it_alarm;
1900 static struct itimerval it_prof;
1902 /* Timer IDs as returned by MM */
1903 MMRESULT tid_alarm = 0;
1904 MMRESULT tid_prof = 0;
1906 static void CALLBACK timer_proc (UINT uID, UINT uMsg, DWORD dwUser,
1907 DWORD dw1, DWORD dw2)
1909 /* Just raise a signal indicated by dwUser parameter */
1910 mswindows_raise (dwUser);
1913 /* Divide time in ms specified by IT by DENOM. Return 1 ms
1914 if division results in zero */
1915 static UINT period (const struct itimerval* it, UINT denom)
1917 static TIMECAPS time_caps;
1920 const struct timeval* tv =
1921 (it->it_value.tv_sec == 0 && it->it_value.tv_usec == 0)
1922 ? &it->it_interval : &it->it_value;
1924 /* Zero means stop timer */
1925 if (tv->tv_sec == 0 && tv->tv_usec == 0)
1928 /* Convert to ms and divide by denom */
1929 res = (tv->tv_sec * 1000 + (tv->tv_usec + 500) / 1000) / denom;
1931 /* Converge to minimum timer resolution */
1932 if (time_caps.wPeriodMin == 0)
1933 timeGetDevCaps (&time_caps, sizeof(time_caps));
1935 if (res < time_caps.wPeriodMin)
1936 res = time_caps.wPeriodMin;
1941 static int setitimer_helper (const struct itimerval* itnew,
1942 struct itimerval* itold, struct itimerval* itcurrent,
1943 MMRESULT* tid, DWORD sigkind)
1945 UINT delay, resolution, event_type;
1947 /* First stop the old timer */
1950 timeKillEvent (*tid);
1951 timeEndPeriod (period (itcurrent, timer_prec));
1955 /* Return old itimerval if requested */
1957 *itold = *itcurrent;
1959 *itcurrent = *itnew;
1961 /* Determine if to start new timer */
1962 delay = period (itnew, 1);
1965 resolution = period (itnew, timer_prec);
1966 event_type = (itnew->it_value.tv_sec == 0 && itnew->it_value.tv_usec == 0)
1967 ? TIME_ONESHOT : TIME_PERIODIC;
1968 timeBeginPeriod (resolution);
1969 *tid = timeSetEvent (delay, resolution, timer_proc, sigkind, event_type);
1972 return !delay || *tid;
1975 int setitimer (int kind, const struct itimerval* itnew,
1976 struct itimerval* itold)
1978 /* In this version, both interval and value are allowed
1979 only if they are equal. */
1980 assert ((itnew->it_value.tv_sec == 0 && itnew->it_value.tv_usec == 0)
1981 || (itnew->it_interval.tv_sec == 0 && itnew->it_interval.tv_usec == 0)
1982 || (itnew->it_value.tv_sec == itnew->it_interval.tv_sec &&
1983 itnew->it_value.tv_usec == itnew->it_interval.tv_usec));
1985 if (kind == ITIMER_REAL)
1986 return setitimer_helper (itnew, itold, &it_alarm, &tid_alarm, SIGALRM);
1987 else if (kind == ITIMER_PROF)
1988 return setitimer_helper (itnew, itold, &it_prof, &tid_prof, SIGPROF);
1990 return errno = EINVAL;
1994 /*--------------------------------------------------------------------*/
1995 /* Memory-mapped files */
1996 /*--------------------------------------------------------------------*/
1999 open_input_file (file_data *p_file, const char *filename)
2001 /* Synched with FSF 20.6. We fixed some warnings. */
2003 HANDLE file_mapping;
2005 DWORD size, upper_size;
2007 file = CreateFile (filename, GENERIC_READ, FILE_SHARE_READ, NULL,
2008 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
2009 if (file == INVALID_HANDLE_VALUE)
2012 size = GetFileSize (file, &upper_size);
2013 file_mapping = CreateFileMapping (file, NULL, PAGE_READONLY,
2018 file_base = MapViewOfFile (file_mapping, FILE_MAP_READ, 0, 0, size);
2022 p_file->name = (char *)filename;
2023 p_file->size = size;
2024 p_file->file = file;
2025 p_file->file_mapping = file_mapping;
2026 p_file->file_base = (char *)file_base;
2032 open_output_file (file_data *p_file, const char *filename, unsigned long size)
2034 /* Synched with FSF 20.6. We fixed some warnings. */
2036 HANDLE file_mapping;
2039 file = CreateFile (filename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
2040 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
2041 if (file == INVALID_HANDLE_VALUE)
2044 file_mapping = CreateFileMapping (file, NULL, PAGE_READWRITE,
2049 file_base = MapViewOfFile (file_mapping, FILE_MAP_WRITE, 0, 0, size);
2050 if (file_base == NULL)
2053 p_file->name = filename;
2054 p_file->size = size;
2055 p_file->file = file;
2056 p_file->file_mapping = file_mapping;
2057 p_file->file_base = (char*) file_base;
2062 #if 1 /* !defined(MINGW) */
2063 /* Return pointer to section header for section containing the given
2064 relative virtual address. */
2065 static IMAGE_SECTION_HEADER *
2066 rva_to_section (DWORD rva, IMAGE_NT_HEADERS * nt_header)
2068 /* Synched with FSF 20.6. We added MINGW stuff. */
2069 PIMAGE_SECTION_HEADER section;
2072 section = IMAGE_FIRST_SECTION (nt_header);
2074 for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
2076 /* Some linkers (eg. the NT SDK linker I believe) swapped the
2077 meaning of these two values - or rather, they ignored
2078 VirtualSize entirely and always set it to zero. This affects
2079 some very old exes (eg. gzip dated Dec 1993). Since
2080 mswindows_executable_type relies on this function to work reliably,
2081 we need to cope with this. */
2082 DWORD real_size = max (section->SizeOfRawData,
2083 section->Misc.VirtualSize);
2084 if (rva >= section->VirtualAddress
2085 && rva < section->VirtualAddress + real_size)
2094 mswindows_executable_type (const char * filename, int * is_dos_app,
2095 int * is_cygnus_app)
2097 /* Synched with FSF 20.6. We added MINGW stuff and casts. */
2098 file_data executable;
2101 /* Default values in case we can't tell for sure. */
2102 *is_dos_app = FALSE;
2103 *is_cygnus_app = FALSE;
2105 if (!open_input_file (&executable, filename))
2108 p = strrchr (filename, '.');
2110 /* We can only identify DOS .com programs from the extension. */
2111 if (p && stricmp (p, ".com") == 0)
2113 else if (p && (stricmp (p, ".bat") == 0 ||
2114 stricmp (p, ".cmd") == 0))
2116 /* A DOS shell script - it appears that CreateProcess is happy to
2117 accept this (somewhat surprisingly); presumably it looks at
2118 COMSPEC to determine what executable to actually invoke.
2119 Therefore, we have to do the same here as well. */
2120 /* Actually, I think it uses the program association for that
2121 extension, which is defined in the registry. */
2122 p = egetenv ("COMSPEC");
2124 mswindows_executable_type (p, is_dos_app, is_cygnus_app);
2128 /* Look for DOS .exe signature - if found, we must also check that
2129 it isn't really a 16- or 32-bit Windows exe, since both formats
2130 start with a DOS program stub. Note that 16-bit Windows
2131 executables use the OS/2 1.x format. */
2133 #if 0 /* defined( MINGW ) */
2134 /* mingw32 doesn't have enough headers to detect cygwin
2135 apps, just do what we can. */
2136 FILHDR * exe_header;
2138 exe_header = (FILHDR*) executable.file_base;
2139 if (exe_header->e_magic != DOSMAGIC)
2142 if ((char*) exe_header->e_lfanew > (char*) executable.size)
2144 /* Some dos headers (pkunzip) have bogus e_lfanew fields. */
2147 else if (exe_header->nt_signature != NT_SIGNATURE)
2152 IMAGE_DOS_HEADER * dos_header;
2153 IMAGE_NT_HEADERS * nt_header;
2155 dos_header = (PIMAGE_DOS_HEADER) executable.file_base;
2156 if (dos_header->e_magic != IMAGE_DOS_SIGNATURE)
2159 nt_header = (PIMAGE_NT_HEADERS) ((char*) dos_header + dos_header->e_lfanew);
2161 if ((char*) nt_header > (char*) dos_header + executable.size)
2163 /* Some dos headers (pkunzip) have bogus e_lfanew fields. */
2166 else if (nt_header->Signature != IMAGE_NT_SIGNATURE &&
2167 LOWORD (nt_header->Signature) != IMAGE_OS2_SIGNATURE)
2171 else if (nt_header->Signature == IMAGE_NT_SIGNATURE)
2173 /* Look for cygwin.dll in DLL import list. */
2174 IMAGE_DATA_DIRECTORY import_dir =
2175 nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
2176 IMAGE_IMPORT_DESCRIPTOR * imports;
2177 IMAGE_SECTION_HEADER * section;
2179 section = rva_to_section (import_dir.VirtualAddress, nt_header);
2180 imports = (IMAGE_IMPORT_DESCRIPTOR *) RVA_TO_PTR (import_dir.VirtualAddress,
2181 section, executable);
2183 for ( ; imports->Name; imports++)
2185 char *dllname = (char*) RVA_TO_PTR (imports->Name, section, executable);
2187 /* The exact name of the cygwin dll has changed with
2188 various releases, but hopefully this will be reasonably
2190 if (strncmp (dllname, "cygwin", 6) == 0)
2192 *is_cygnus_app = TRUE;
2201 close_file_data (&executable);
2204 /* Close the system structures associated with the given file. */
2206 close_file_data (file_data *p_file)
2208 UnmapViewOfFile (p_file->file_base);
2209 CloseHandle (p_file->file_mapping);
2210 CloseHandle (p_file->file);
2216 DEFVAR_INT ("nt-fake-unix-uid", &nt_fake_unix_uid /*
2217 *Set uid returned by `user-uid' and `user-real-uid'.
2218 Under NT and 9x, there is no uids, and even no almighty user called root.
2219 By setting this variable, you can have any uid of choice. Default is 0.
2220 Changes to this variable take effect immediately.
2222 nt_fake_unix_uid = 0;