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> */
35 #include "syssignal.h"
50 #include "syswindows.h"
57 extern Lisp_Object Vmswindows_downcase_file_names;
59 extern Lisp_Object Vwin32_generate_fake_inodes;
61 extern Lisp_Object Vmswindows_get_true_file_attributes;
65 static char startup_dir[ MAXPATHLEN ];
67 /* Get the current working directory. */
72 if (GetCurrentDirectory (MAXPATHLEN, dir) > 0)
76 /* Emacs doesn't actually change directory itself, and we want to
77 force our real wd to be where emacs.exe is to avoid unnecessary
78 conflicts when trying to rename or delete directories. */
79 strcpy (dir, startup_dir);
84 /* Emulate getloadavg. */
86 getloadavg (double loadavg[], int nelem)
90 /* A faithful emulation is going to have to be saved for a rainy day. */
91 for (i = 0; i < nelem; i++)
98 /* Emulate getpwuid, getpwnam and others. */
100 #define PASSWD_FIELD_SIZE 256
102 static char the_passwd_name[PASSWD_FIELD_SIZE];
103 static char the_passwd_passwd[PASSWD_FIELD_SIZE];
104 static char the_passwd_gecos[PASSWD_FIELD_SIZE];
105 static char the_passwd_dir[PASSWD_FIELD_SIZE];
106 static char the_passwd_shell[PASSWD_FIELD_SIZE];
108 static struct passwd the_passwd =
123 return nt_fake_unix_uid;
129 return nt_fake_unix_uid;
135 return the_passwd.pw_gid;
147 if (uid == nt_fake_unix_uid)
149 the_passwd.pw_gid = the_passwd.pw_uid = uid;
157 getpwnam (const char *name)
161 pw = getpwuid (getuid ());
165 if (stricmp (name, pw->pw_name))
172 init_user_info (void)
174 /* This code is pretty much of ad hoc nature. There is no unix-like
175 UIDs under Windows NT. There is no concept of root user, because
176 all security is ACL-based. Instead, let's use a simple variable,
177 nt-fake-unix-uid, which would allow the user to have a uid of
178 choice. --kkm, 02/03/2000 */
180 /* Find the user's real name by opening the process token and
181 looking up the name associated with the user-sid in that token.
183 Use the relative portion of the identifier authority value from
184 the user-sid as the user id value (same for group id using the
185 primary group sid from the process token). */
187 char user_sid[256], name[256], domain[256];
188 DWORD length = sizeof (name), dlength = sizeof (domain), trash;
190 SID_NAME_USE user_type;
192 if (OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY, &token)
193 && GetTokenInformation (token, TokenUser,
194 (PVOID) user_sid, sizeof (user_sid), &trash)
195 && LookupAccountSid (NULL, *((PSID *) user_sid), name, &length,
196 domain, &dlength, &user_type))
198 strcpy (the_passwd.pw_name, name);
199 /* Determine a reasonable uid value. */
200 if (stricmp ("administrator", name) == 0)
202 the_passwd.pw_uid = 0;
203 the_passwd.pw_gid = 0;
207 SID_IDENTIFIER_AUTHORITY * pSIA;
209 pSIA = GetSidIdentifierAuthority (*((PSID *) user_sid));
210 /* I believe the relative portion is the last 4 bytes (of 6)
212 the_passwd.pw_uid = ((pSIA->Value[2] << 24) +
213 (pSIA->Value[3] << 16) +
214 (pSIA->Value[4] << 8) +
215 (pSIA->Value[5] << 0));
216 /* restrict to conventional uid range for normal users */
217 the_passwd.pw_uid = the_passwd.pw_uid % 60001;
220 if (GetTokenInformation (token, TokenPrimaryGroup,
221 (PVOID) user_sid, sizeof (user_sid), &trash))
223 SID_IDENTIFIER_AUTHORITY * pSIA;
225 pSIA = GetSidIdentifierAuthority (*((PSID *) user_sid));
226 the_passwd.pw_gid = ((pSIA->Value[2] << 24) +
227 (pSIA->Value[3] << 16) +
228 (pSIA->Value[4] << 8) +
229 (pSIA->Value[5] << 0));
230 /* I don't know if this is necessary, but for safety... */
231 the_passwd.pw_gid = the_passwd.pw_gid % 60001;
234 the_passwd.pw_gid = the_passwd.pw_uid;
237 /* If security calls are not supported (presumably because we
238 are running under Windows 95), fallback to this. */
239 else if (GetUserName (name, &length))
241 strcpy (the_passwd.pw_name, name);
242 if (stricmp ("administrator", name) == 0)
243 the_passwd.pw_uid = 0;
245 the_passwd.pw_uid = 123;
246 the_passwd.pw_gid = the_passwd.pw_uid;
250 strcpy (the_passwd.pw_name, "unknown");
251 the_passwd.pw_uid = 123;
252 the_passwd.pw_gid = 123;
258 /* Obtain only logon id here, uid part is moved to getuid */
260 DWORD length = sizeof (name);
261 if (GetUserName (name, &length))
262 strcpy (the_passwd.pw_name, name);
264 strcpy (the_passwd.pw_name, "unknown");
267 /* Ensure HOME and SHELL are defined. */
270 * With XEmacs, setting $HOME is deprecated.
272 if (getenv ("HOME") == NULL)
275 if (getenv ("SHELL") == NULL)
276 putenv ((GetVersion () & 0x80000000) ? "SHELL=command" : "SHELL=cmd");
278 /* Set dir and shell from environment variables. */
279 strcpy (the_passwd.pw_dir, (char *)get_home_directory());
280 strcpy (the_passwd.pw_shell, getenv ("SHELL"));
283 /* Normalize filename by converting all path separators to
284 the specified separator. Also conditionally convert upper
285 case path name components to lower case. */
288 normalize_filename (char *fp, char path_sep)
293 /* Always lower-case drive letters a-z, even if the filesystem
294 preserves case in filenames.
295 This is so filenames can be compared by string comparison
296 functions that are case-sensitive. Even case-preserving filesystems
297 do not distinguish case in drive letters. */
298 if (fp[1] == ':' && *fp >= 'A' && *fp <= 'Z')
304 if (NILP (Vmswindows_downcase_file_names))
308 if (*fp == '/' || *fp == '\\')
315 sep = path_sep; /* convert to this path separator */
316 elem = fp; /* start of current path element */
319 if (*fp >= 'a' && *fp <= 'z')
320 elem = 0; /* don't convert this element */
322 if (*fp == 0 || *fp == ':')
324 sep = *fp; /* restore current separator (or 0) */
325 *fp = '/'; /* after conversion of this element */
328 if (*fp == '/' || *fp == '\\')
330 if (elem && elem != fp)
332 *fp = 0; /* temporary end of string */
333 _strlwr (elem); /* while we convert to lower case */
335 *fp = sep; /* convert (or restore) path separator */
336 elem = fp + 1; /* next element starts after separator */
342 /* Destructively turn backslashes into slashes. */
344 dostounix_filename (char *p)
346 normalize_filename (p, '/');
349 /* Destructively turn slashes into backslashes. */
351 unixtodos_filename (char *p)
353 normalize_filename (p, '\\');
356 /* Remove all CR's that are followed by a LF.
357 (From msdos.c...probably should figure out a way to share it,
358 although this code isn't going to ever change.) */
360 crlf_to_lf (int n, unsigned char *buf, unsigned *lf_count)
362 unsigned char *np = buf;
363 unsigned char *startp = buf;
364 unsigned char *endp = buf + n;
368 while (buf < endp - 1)
374 if (*(++buf) != 0x0a)
389 /* Parse the root part of file name, if present. Return length and
390 optionally store pointer to char after root. */
392 parse_root (char * name, char ** pPath)
399 /* find the root name of the volume if given */
400 if (isalpha (name[0]) && name[1] == ':')
402 /* skip past drive specifier */
404 if (IS_DIRECTORY_SEP (name[0]))
407 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
413 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
418 if (IS_DIRECTORY_SEP (name[0]))
428 /* Get long base name for name; name is assumed to be absolute. */
430 get_long_basename (char * name, char * buf, int size)
432 WIN32_FIND_DATA find_data;
438 /* If the last component of NAME has a wildcard character,
439 return it as the basename. */
440 p = name + strlen (name);
441 while (*p != '\\' && *p != ':' && p > name) p--;
443 if (strchr (p, '*') || strchr (p, '?'))
445 if ((len = strlen (p)) < size)
446 memcpy (buf, p, len + 1);
453 dir_handle = FindFirstFile (name, &find_data);
454 if (dir_handle != INVALID_HANDLE_VALUE)
456 if ((len = strlen (find_data.cFileName)) < size)
457 memcpy (buf, find_data.cFileName, len + 1);
460 FindClose (dir_handle);
465 /* Get long name for file, if possible (assumed to be absolute). */
467 win32_get_long_filename (char * name, char * buf, int size)
472 char full[ MAX_PATH ];
479 /* Use local copy for destructive modification. */
480 memcpy (full, name, len+1);
481 unixtodos_filename (full);
483 /* Copy root part verbatim. */
484 len = parse_root (full, &p);
485 memcpy (o, full, len);
492 p = strchr (q, '\\');
494 len = get_long_basename (full, o, size);
512 while (p != NULL && *p);
518 /* Routines that are no-ops on NT but are defined to get Emacs to compile. */
520 #if 0 /* #### We do not need those, do we? -kkm */
522 unrequest_sigio (void)
534 #define REG_ROOT "SOFTWARE\\GNU\\XEmacs"
537 nt_get_resource (char *key, LPDWORD lpdwtype)
540 HKEY hrootkey = NULL;
543 /* Check both the current user and the local machine to see if
544 we have any resources. */
546 if (RegOpenKeyEx (HKEY_CURRENT_USER, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
550 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
551 && (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL
552 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
557 if (lpvalue) xfree (lpvalue);
559 RegCloseKey (hrootkey);
562 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
566 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS &&
567 (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL &&
568 RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
573 if (lpvalue) xfree (lpvalue);
575 RegCloseKey (hrootkey);
582 init_environment (void)
584 /* Check for environment variables and use registry if they don't exist */
590 static char * env_vars[] =
604 #if defined (HEAP_IN_DATA) && !defined(PDUMP)
605 cache_system_info ();
607 for (i = 0; i < countof (env_vars); i++)
609 if (!getenv (env_vars[i]) &&
610 (lpval = nt_get_resource (env_vars[i], &dwType)) != NULL)
612 if (dwType == REG_EXPAND_SZ)
614 char buf1[500], buf2[500];
616 ExpandEnvironmentStrings ((LPSTR) lpval, buf1, 500);
617 _snprintf (buf2, 499, "%s=%s", env_vars[i], buf1);
618 putenv (strdup (buf2));
620 else if (dwType == REG_SZ)
624 _snprintf (buf, 499, "%s=%s", env_vars[i], lpval);
625 putenv (strdup (buf));
633 /* Another special case: on NT, the PATH variable is actually named
634 "Path" although cmd.exe (perhaps NT itself) arranges for
635 environment variable lookup and setting to be case insensitive.
636 However, Emacs assumes a fully case sensitive environment, so we
637 need to change "Path" to "PATH" to match the expectations of
638 various elisp packages. We do this by the sneaky method of
639 modifying the string in the C runtime environ entry.
641 The same applies to COMSPEC. */
645 for (envp = environ; *envp; envp++)
646 if (_strnicmp (*envp, "PATH=", 5) == 0)
647 memcpy (*envp, "PATH=", 5);
648 else if (_strnicmp (*envp, "COMSPEC=", 8) == 0)
649 memcpy (*envp, "COMSPEC=", 8);
652 /* Remember the initial working directory for getwd, then make the
653 real wd be the location of emacs.exe to avoid conflicts when
654 renaming or deleting directories. (We also don't call chdir when
655 running subprocesses for the same reason.) */
656 if (!GetCurrentDirectory (MAXPATHLEN, startup_dir))
661 char modname[MAX_PATH];
663 if (!GetModuleFileName (NULL, modname, MAX_PATH))
665 if ((p = strrchr (modname, '\\')) == NULL)
669 SetCurrentDirectory (modname);
675 #ifndef HAVE_X_WINDOWS
676 /* X11R6 on NT provides the single parameter version of this command. */
678 #include <sys/timeb.h>
680 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
682 gettimeofday (struct timeval *tv, struct timezone *tz)
687 tv->tv_sec = tb.time;
688 tv->tv_usec = tb.millitm * 1000L;
691 tz->tz_minuteswest = tb.timezone; /* minutes west of Greenwich */
692 tz->tz_dsttime = tb.dstflag; /* type of dst correction */
696 #endif /* HAVE_X_WINDOWS */
698 /* ------------------------------------------------------------------------- */
699 /* IO support and wrapper functions for Win32 API. */
700 /* ------------------------------------------------------------------------- */
702 /* Place a wrapper around the MSVC version of ctime. It returns NULL
703 on network directories, so we handle that case here.
704 (Ulrich Leodolter, 1/11/95). */
706 sys_ctime (const time_t *t)
708 char *str = (char *) ctime (t);
709 return (str ? str : "Sun Jan 01 00:00:00 1970");
712 /* Emulate sleep...we could have done this with a define, but that
713 would necessitate including windows.h in the files that used it.
714 This is much easier. */
716 #ifndef HAVE_X_WINDOWS
718 sys_sleep (int seconds)
720 Sleep (seconds * 1000);
724 /* #### This is an evil dirty hack. We must get rid of it.
725 Word "munging" is not in XEmacs lexicon. - kkm */
727 /* Internal MSVC data and functions for low-level descriptor munging */
728 #if (_MSC_VER == 900)
729 extern char _osfile[];
731 extern int __cdecl _set_osfhnd (int fd, long h);
732 extern int __cdecl _free_osfhnd (int fd);
734 /* parallel array of private info on file handles */
735 filedesc fd_info [ MAXDESC ];
737 typedef struct volume_info_data {
738 struct volume_info_data * next;
740 /* time when info was obtained */
743 /* actual volume info */
752 /* Global referenced by various functions. */
753 static volume_info_data volume_info;
755 /* Vector to indicate which drives are local and fixed (for which cached
756 data never expires). */
757 static BOOL fixed_drives[26];
759 /* Consider cached volume information to be stale if older than 10s,
760 at least for non-local drives. Info for fixed drives is never stale. */
761 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
762 #define VOLINFO_STILL_VALID( root_dir, info ) \
763 ( ( isalpha (root_dir[0]) && \
764 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
765 || GetTickCount () - info->timestamp < 10000 )
767 /* Cache support functions. */
769 /* Simple linked list with linear search is sufficient. */
770 static volume_info_data *volume_cache = NULL;
772 static volume_info_data *
773 lookup_volume_info (char * root_dir)
775 volume_info_data * info;
777 for (info = volume_cache; info; info = info->next)
778 if (stricmp (info->root_dir, root_dir) == 0)
784 add_volume_info (char * root_dir, volume_info_data * info)
786 info->root_dir = xstrdup (root_dir);
787 info->next = volume_cache;
792 /* Wrapper for GetVolumeInformation, which uses caching to avoid
793 performance penalty (~2ms on 486 for local drives, 7.5ms for local
794 cdrom drive, ~5-10ms or more for remote drives on LAN). */
796 GetCachedVolumeInformation (char * root_dir)
798 volume_info_data * info;
799 char default_root[ MAX_PATH ];
801 /* NULL for root_dir means use root from current directory. */
802 if (root_dir == NULL)
804 if (GetCurrentDirectory (MAX_PATH, default_root) == 0)
806 parse_root (default_root, &root_dir);
808 root_dir = default_root;
811 /* Local fixed drives can be cached permanently. Removable drives
812 cannot be cached permanently, since the volume name and serial
813 number (if nothing else) can change. Remote drives should be
814 treated as if they are removable, since there is no sure way to
815 tell whether they are or not. Also, the UNC association of drive
816 letters mapped to remote volumes can be changed at any time (even
817 by other processes) without notice.
819 As a compromise, so we can benefit from caching info for remote
820 volumes, we use a simple expiry mechanism to invalidate cache
821 entries that are more than ten seconds old. */
824 /* No point doing this, because WNetGetConnection is even slower than
825 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
826 GetDriveType is about the only call of this type which does not
827 involve network access, and so is extremely quick). */
829 /* Map drive letter to UNC if remote. */
830 if ( isalpha( root_dir[0] ) && !fixed[ DRIVE_INDEX( root_dir[0] ) ] )
832 char remote_name[ 256 ];
833 char drive[3] = { root_dir[0], ':' };
835 if (WNetGetConnection (drive, remote_name, sizeof (remote_name))
841 info = lookup_volume_info (root_dir);
843 if (info == NULL || ! VOLINFO_STILL_VALID (root_dir, info))
851 /* Info is not cached, or is stale. */
852 if (!GetVolumeInformation (root_dir,
857 type, sizeof (type)))
860 /* Cache the volume information for future use, overwriting existing
864 info = (volume_info_data *) xmalloc (sizeof (volume_info_data));
865 add_volume_info (root_dir, info);
873 info->name = xstrdup (name);
874 info->serialnum = serialnum;
875 info->maxcomp = maxcomp;
877 info->type = xstrdup (type);
878 info->timestamp = GetTickCount ();
884 /* Get information on the volume where name is held; set path pointer to
885 start of pathname in name (past UNC header\volume header if present). */
887 get_volume_info (const char * name, const char ** pPath)
890 char *rootname = NULL; /* default to current volume */
891 volume_info_data * info;
896 /* find the root name of the volume if given */
897 if (isalpha (name[0]) && name[1] == ':')
905 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
912 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
925 info = GetCachedVolumeInformation (rootname);
928 /* Set global referenced by other functions. */
935 /* Determine if volume is FAT format (ie. only supports short 8.3
936 names); also set path pointer to start of pathname in name. */
938 is_fat_volume (const char * name, const char ** pPath)
940 if (get_volume_info (name, pPath))
941 return (volume_info.maxcomp == 12);
945 /* Map filename to a legal 8.3 name if necessary. */
947 map_win32_filename (const char * name, const char ** pPath)
949 static char shortname[MAX_PATH];
950 char * str = shortname;
953 const char * save_name = name;
955 if (is_fat_volume (name, &path)) /* truncate to 8.3 */
957 REGISTER int left = 8; /* maximum number of chars in part */
958 REGISTER int extn = 0; /* extension added? */
959 REGISTER int dots = 2; /* maximum number of dots allowed */
962 *str++ = *name++; /* skip past UNC header */
964 while ((c = *name++))
971 extn = 0; /* reset extension flags */
972 dots = 2; /* max 2 dots */
973 left = 8; /* max length 8 for main part */
977 extn = 0; /* reset extension flags */
978 dots = 2; /* max 2 dots */
979 left = 8; /* max length 8 for main part */
984 /* Convert path components of the form .xxx to _xxx,
985 but leave . and .. as they are. This allows .emacs
986 to be read as _emacs, for example. */
990 IS_DIRECTORY_SEP (*name))
1005 extn = 1; /* we've got an extension */
1006 left = 3; /* 3 chars in extension */
1010 /* any embedded dots after the first are converted to _ */
1015 case '#': /* don't lose these, they're important */
1017 str[-1] = c; /* replace last character of part */
1022 *str++ = tolower (c); /* map to lower case (looks nicer) */
1024 dots = 0; /* started a path component */
1033 strcpy (shortname, name);
1034 unixtodos_filename (shortname);
1038 *pPath = shortname + (path - save_name);
1044 /* Emulate the Unix directory procedures opendir, closedir,
1045 and readdir. We can't use the procedures supplied in sysdep.c,
1046 so we provide them here. */
1048 struct direct dir_static; /* simulated directory contents */
1049 static HANDLE dir_find_handle = INVALID_HANDLE_VALUE;
1050 static int dir_is_fat;
1051 static char dir_pathname[MAXPATHLEN+1];
1052 static WIN32_FIND_DATA dir_find_data;
1055 opendir (const char *filename)
1059 /* Opening is done by FindFirstFile. However, a read is inherent to
1060 this operation, so we defer the open until read time. */
1062 if (!(dirp = xnew_and_zero(DIR)))
1064 if (dir_find_handle != INVALID_HANDLE_VALUE)
1071 strncpy (dir_pathname, map_win32_filename (filename, NULL), MAXPATHLEN);
1072 dir_pathname[MAXPATHLEN] = '\0';
1073 dir_is_fat = is_fat_volume (filename, NULL);
1079 closedir (DIR *dirp)
1081 /* If we have a find-handle open, close it. */
1082 if (dir_find_handle != INVALID_HANDLE_VALUE)
1084 FindClose (dir_find_handle);
1085 dir_find_handle = INVALID_HANDLE_VALUE;
1093 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
1094 if (dir_find_handle == INVALID_HANDLE_VALUE)
1096 char filename[MAXNAMLEN + 3];
1099 strcpy (filename, dir_pathname);
1100 ln = strlen (filename) - 1;
1101 if (!IS_DIRECTORY_SEP (filename[ln]))
1102 strcat (filename, "\\");
1103 strcat (filename, "*");
1105 dir_find_handle = FindFirstFile (filename, &dir_find_data);
1107 if (dir_find_handle == INVALID_HANDLE_VALUE)
1112 if (!FindNextFile (dir_find_handle, &dir_find_data))
1116 /* Emacs never uses this value, so don't bother making it match
1117 value returned by stat(). */
1118 dir_static.d_ino = 1;
1120 dir_static.d_reclen = sizeof (struct direct) - MAXNAMLEN + 3 +
1121 dir_static.d_namlen - dir_static.d_namlen % 4;
1123 dir_static.d_namlen = strlen (dir_find_data.cFileName);
1124 strcpy (dir_static.d_name, dir_find_data.cFileName);
1126 _strlwr (dir_static.d_name);
1127 else if (!NILP (Vmswindows_downcase_file_names))
1130 for (p = dir_static.d_name; *p; p++)
1131 if (*p >= 'a' && *p <= 'z')
1134 _strlwr (dir_static.d_name);
1141 /* #### Have to check if all that sad story about '95 is true - kkm */
1143 sys_rename (const char * oldname, const char * newname)
1145 char temp[MAX_PATH];
1148 /* MoveFile on Win95 doesn't correctly change the short file name
1149 alias in a number of circumstances (it is not easy to predict when
1150 just by looking at oldname and newname, unfortunately). In these
1151 cases, renaming through a temporary name avoids the problem.
1153 A second problem on Win95 is that renaming through a temp name when
1154 newname is uppercase fails (the final long name ends up in
1155 lowercase, although the short alias might be uppercase) UNLESS the
1156 long temp name is not 8.3.
1158 So, on Win95 we always rename through a temp name, and we make sure
1159 the temp name has a long extension to ensure correct renaming. */
1161 strcpy (temp, map_win32_filename (oldname, NULL));
1163 if (GetVersion () & 0x80000000)
1167 if (p = strrchr (temp, '\\'))
1171 /* Force temp name to require a manufactured 8.3 alias - this
1172 seems to make the second rename work properly. */
1173 strcpy (p, "_rename_temp.XXXXXX");
1175 if (rename (map_win32_filename (oldname, NULL), temp) < 0)
1179 /* Emulate Unix behavior - newname is deleted if it already exists
1180 (at least if it is a file; don't do this for directories).
1181 However, don't do this if we are just changing the case of the file
1182 name - we will end up deleting the file we are trying to rename! */
1183 newname = map_win32_filename (newname, NULL);
1185 /* TODO: Use GetInformationByHandle (on NT) to ensure newname and temp
1186 do not refer to the same file, eg. through share aliases. */
1187 if (stricmp (newname, temp) != 0
1188 && (attr = GetFileAttributes (newname)) != -1
1189 && (attr & FILE_ATTRIBUTE_DIRECTORY) == 0)
1191 _chmod (newname, 0666);
1195 return rename (temp, newname);
1199 static FILETIME utc_base_ft;
1200 static int init = 0;
1204 static long double utc_base;
1207 convert_time (FILETIME ft)
1213 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
1222 st.wMilliseconds = 0;
1224 SystemTimeToFileTime (&st, &utc_base_ft);
1225 utc_base = (long double) utc_base_ft.dwHighDateTime
1226 * 4096 * 1024 * 1024 + utc_base_ft.dwLowDateTime;
1230 if (CompareFileTime (&ft, &utc_base_ft) < 0)
1233 ret = (long double) ft.dwHighDateTime * 4096 * 1024 * 1024 + ft.dwLowDateTime;
1235 return (time_t) (ret * 1e-7);
1239 #if defined(__MINGW32__) && CYGWIN_VERSION_DLL_MAJOR <= 21
1240 #define LowPart u.LowPart
1241 #define HighPart u.HighPart
1244 static LARGE_INTEGER utc_base_li;
1247 convert_time (FILETIME uft)
1254 TIME_ZONE_INFORMATION tzi;
1262 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
1271 st.wMilliseconds = 0;
1273 SystemTimeToFileTime (&st, &utc_base_ft);
1275 utc_base_li.LowPart = utc_base_ft.dwLowDateTime;
1276 utc_base_li.HighPart = utc_base_ft.dwHighDateTime;
1283 /* On a compiler that supports long integers, do it the easy way */
1284 lft.LowPart = uft.dwLowDateTime;
1285 lft.HighPart = uft.dwHighDateTime;
1286 ret = (time_t) ((lft.QuadPart - utc_base_li.QuadPart) / 10000000);
1290 /* Do it the hard way using mktime. */
1291 FileTimeToLocalFileTime(&uft, &ft);
1292 FileTimeToSystemTime (&ft, &st);
1293 tzid = GetTimeZoneInformation (&tzi);
1294 t.tm_year = st.wYear - 1900;
1295 t.tm_mon = st.wMonth - 1;
1296 t.tm_mday = st.wDay;
1297 t.tm_hour = st.wHour;
1298 t.tm_min = st.wMinute;
1299 t.tm_sec = st.wSecond;
1300 t.tm_isdst = (tzid == TIME_ZONE_ID_DAYLIGHT);
1301 /* st.wMilliseconds not applicable */
1313 #if defined(__MINGW32__) && CYGWIN_VERSION_DLL_MAJOR <= 21
1319 /* in case we ever have need of this */
1321 convert_from_time_t (time_t time, FILETIME * pft)
1327 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
1336 st.wMilliseconds = 0;
1338 SystemTimeToFileTime (&st, &utc_base_ft);
1339 utc_base = (long double) utc_base_ft.dwHighDateTime
1340 * 4096 * 1024 * 1024 + utc_base_ft.dwLowDateTime;
1344 /* time in 100ns units since 1-Jan-1601 */
1345 tmp = (long double) time * 1e7 + utc_base;
1346 pft->dwHighDateTime = (DWORD) (tmp / (4096.0 * 1024 * 1024));
1347 pft->dwLowDateTime = (DWORD) (tmp - pft->dwHighDateTime);
1352 /* No reason to keep this; faking inode values either by hashing or even
1353 using the file index from GetInformationByHandle, is not perfect and
1354 so by default Emacs doesn't use the inode values on Windows.
1355 Instead, we now determine file-truename correctly (except for
1356 possible drive aliasing etc). */
1358 /* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
1360 hashval (const unsigned char * str)
1365 h = (h << 4) + *str++;
1371 /* Return the hash value of the canonical pathname, excluding the
1372 drive/UNC header, to get a hopefully unique inode number. */
1374 generate_inode_val (const char * name)
1376 char fullname[ MAX_PATH ];
1380 /* Get the truly canonical filename, if it exists. (Note: this
1381 doesn't resolve aliasing due to subst commands, or recognize hard
1383 if (!win32_get_long_filename ((char *)name, fullname, MAX_PATH))
1386 parse_root (fullname, &p);
1387 /* Normal Win32 filesystems are still case insensitive. */
1394 /* stat has been fixed since MSVC 5.0.
1395 Oh, and do not encapsulater stat for non-MS compilers, too */
1396 /* #### popineau@ese-metz.fr says they still might be broken.
1397 Oh well... Let's add that `1 ||' condition.... --kkm */
1398 /* #### aichner@ecf.teradyne.com reported that with the library
1399 provided stat/fstat, (file-exist "d:\\tmp\\") =>> nil,
1400 (file-exist "d:\\tmp") =>> t, when d:\tmp exists. Whenever
1401 we opt to use non-encapsulated stat(), this should serve as
1402 a compatibility test. --kkm */
1404 #if 1 || defined(_MSC_VER) && _MSC_VER < 1100
1406 /* Since stat is encapsulated on Windows NT, we need to encapsulate
1407 the equally broken fstat as well. */
1409 fstat (int handle, struct stat *buffer)
1412 BY_HANDLE_FILE_INFORMATION lpFileInfo;
1413 /* Initialize values */
1414 buffer->st_mode = 0;
1415 buffer->st_size = 0;
1417 buffer->st_rdev = 0;
1418 buffer->st_atime = 0;
1419 buffer->st_ctime = 0;
1420 buffer->st_mtime = 0;
1421 buffer->st_nlink = 0;
1422 ret = GetFileInformationByHandle((HANDLE) _get_osfhandle(handle), &lpFileInfo);
1429 buffer->st_mtime = convert_time (lpFileInfo.ftLastWriteTime);
1430 buffer->st_atime = convert_time (lpFileInfo.ftLastAccessTime);
1431 if (buffer->st_atime == 0) buffer->st_atime = buffer->st_mtime;
1432 buffer->st_ctime = convert_time (lpFileInfo.ftCreationTime);
1433 if (buffer->st_ctime == 0) buffer->st_ctime = buffer->st_mtime;
1434 buffer->st_size = lpFileInfo.nFileSizeLow;
1435 buffer->st_nlink = (short) lpFileInfo.nNumberOfLinks;
1440 /* MSVC stat function can't cope with UNC names and has other bugs, so
1441 replace it with our own. This also allows us to calculate consistent
1442 inode values without hacks in the main Emacs code. */
1444 stat (const char * path, struct stat * buf)
1447 WIN32_FIND_DATA wfd;
1452 int rootdir = FALSE;
1454 if (path == NULL || buf == NULL)
1460 name = (char *) map_win32_filename (path, &path);
1461 /* must be valid filename, no wild cards */
1462 if (strchr (name, '*') || strchr (name, '?'))
1468 /* Remove trailing directory separator, unless name is the root
1469 directory of a drive or UNC volume in which case ensure there
1470 is a trailing separator. */
1471 len = strlen (name);
1472 rootdir = (path >= name + len - 1
1473 && (IS_DIRECTORY_SEP (*path) || *path == 0));
1474 name = strcpy ((char *)alloca (len + 2), name);
1478 if (!IS_DIRECTORY_SEP (name[len-1]))
1479 strcat (name, "\\");
1480 if (GetDriveType (name) < 2)
1485 memset (&wfd, 0, sizeof (wfd));
1486 wfd.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
1487 wfd.ftCreationTime = utc_base_ft;
1488 wfd.ftLastAccessTime = utc_base_ft;
1489 wfd.ftLastWriteTime = utc_base_ft;
1490 strcpy (wfd.cFileName, name);
1494 if (IS_DIRECTORY_SEP (name[len-1]))
1497 /* (This is hacky, but helps when doing file completions on
1498 network drives.) Optimize by using information available from
1499 active readdir if possible. */
1500 if (dir_find_handle != INVALID_HANDLE_VALUE &&
1501 (len = strlen (dir_pathname)),
1502 strnicmp (name, dir_pathname, len) == 0 &&
1503 IS_DIRECTORY_SEP (name[len]) &&
1504 stricmp (name + len + 1, dir_static.d_name) == 0)
1506 /* This was the last entry returned by readdir. */
1507 wfd = dir_find_data;
1511 fh = FindFirstFile (name, &wfd);
1512 if (fh == INVALID_HANDLE_VALUE)
1521 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1523 buf->st_mode = _S_IFDIR;
1524 buf->st_nlink = 2; /* doesn't really matter */
1525 fake_inode = 0; /* this doesn't either I think */
1527 else if (!NILP (Vmswindows_get_true_file_attributes))
1529 /* This is more accurate in terms of getting the correct number
1530 of links, but is quite slow (it is noticeable when Emacs is
1531 making a list of file name completions). */
1532 BY_HANDLE_FILE_INFORMATION info;
1534 /* No access rights required to get info. */
1535 fh = CreateFile (name, 0, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
1536 OPEN_EXISTING, 0, NULL);
1538 if (GetFileInformationByHandle (fh, &info))
1540 switch (GetFileType (fh))
1542 case FILE_TYPE_DISK:
1543 buf->st_mode = _S_IFREG;
1545 case FILE_TYPE_PIPE:
1546 buf->st_mode = _S_IFIFO;
1548 case FILE_TYPE_CHAR:
1549 case FILE_TYPE_UNKNOWN:
1551 buf->st_mode = _S_IFCHR;
1553 buf->st_nlink = (short) info.nNumberOfLinks;
1554 /* Might as well use file index to fake inode values, but this
1555 is not guaranteed to be unique unless we keep a handle open
1556 all the time (even then there are situations where it is
1557 not unique). Reputedly, there are at most 48 bits of info
1558 (on NTFS, presumably less on FAT). */
1559 fake_inode = info.nFileIndexLow ^ info.nFileIndexHigh;
1570 /* Don't bother to make this information more accurate. */
1571 buf->st_mode = _S_IFREG;
1577 /* Not sure if there is any point in this. */
1578 if (!NILP (Vwin32_generate_fake_inodes))
1579 fake_inode = generate_inode_val (name);
1580 else if (fake_inode == 0)
1582 /* For want of something better, try to make everything unique. */
1583 static DWORD gen_num = 0;
1584 fake_inode = ++gen_num;
1588 /* #### MSVC defines _ino_t to be short; other libc's might not. */
1589 buf->st_ino = (unsigned short) (fake_inode ^ (fake_inode >> 16));
1591 /* consider files to belong to current user */
1592 buf->st_uid = buf->st_gid = nt_fake_unix_uid;
1594 /* volume_info is set indirectly by map_win32_filename */
1595 buf->st_dev = volume_info.serialnum;
1596 buf->st_rdev = volume_info.serialnum;
1598 buf->st_size = wfd.nFileSizeLow;
1600 /* Convert timestamps to Unix format. */
1601 buf->st_mtime = convert_time (wfd.ftLastWriteTime);
1602 buf->st_atime = convert_time (wfd.ftLastAccessTime);
1603 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
1604 buf->st_ctime = convert_time (wfd.ftCreationTime);
1605 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
1607 /* determine rwx permissions */
1608 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
1609 permission = _S_IREAD;
1611 permission = _S_IREAD | _S_IWRITE;
1613 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1614 permission |= _S_IEXEC;
1617 char * p = strrchr (name, '.');
1619 (stricmp (p, ".exe") == 0 ||
1620 stricmp (p, ".com") == 0 ||
1621 stricmp (p, ".bat") == 0 ||
1622 stricmp (p, ".cmd") == 0))
1623 permission |= _S_IEXEC;
1626 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
1630 #endif /* defined(_MSC_VER) && _MSC_VER < 1100 */
1632 /* From callproc.c */
1633 extern Lisp_Object Vbinary_process_input;
1634 extern Lisp_Object Vbinary_process_output;
1636 /* Unix pipe() has only one arg */
1638 sys_pipe (int * phandles)
1643 /* make pipe handles non-inheritable; when we spawn a child, we
1644 replace the relevant handle with an inheritable one. Also put
1645 pipes into binary mode; we will do text mode translation ourselves
1647 rc = _pipe (phandles, 0, _O_NOINHERIT | _O_BINARY);
1651 flags = FILE_PIPE | FILE_READ;
1652 if (!NILP (Vbinary_process_output))
1653 flags |= FILE_BINARY;
1654 fd_info[phandles[0]].flags = flags;
1656 flags = FILE_PIPE | FILE_WRITE;
1657 if (!NILP (Vbinary_process_input))
1658 flags |= FILE_BINARY;
1659 fd_info[phandles[1]].flags = flags;
1666 term_ntproc (int unused)
1673 /* Initial preparation for subprocess support: replace our standard
1674 handles with non-inheritable versions. */
1677 HANDLE stdin_save = INVALID_HANDLE_VALUE;
1678 HANDLE stdout_save = INVALID_HANDLE_VALUE;
1679 HANDLE stderr_save = INVALID_HANDLE_VALUE;
1681 parent = GetCurrentProcess ();
1683 /* ignore errors when duplicating and closing; typically the
1684 handles will be invalid when running as a gui program. */
1685 DuplicateHandle (parent,
1686 GetStdHandle (STD_INPUT_HANDLE),
1691 DUPLICATE_SAME_ACCESS);
1693 DuplicateHandle (parent,
1694 GetStdHandle (STD_OUTPUT_HANDLE),
1699 DUPLICATE_SAME_ACCESS);
1701 DuplicateHandle (parent,
1702 GetStdHandle (STD_ERROR_HANDLE),
1707 DUPLICATE_SAME_ACCESS);
1713 if (stdin_save != INVALID_HANDLE_VALUE)
1714 _open_osfhandle ((long) stdin_save, O_TEXT);
1716 _open ("nul", O_TEXT | O_NOINHERIT | O_RDONLY);
1719 if (stdout_save != INVALID_HANDLE_VALUE)
1720 _open_osfhandle ((long) stdout_save, O_TEXT);
1722 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
1725 if (stderr_save != INVALID_HANDLE_VALUE)
1726 _open_osfhandle ((long) stderr_save, O_TEXT);
1728 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
1732 /* unfortunately, atexit depends on implementation of malloc */
1733 /* atexit (term_ntproc); */
1734 signal (SIGABRT, term_ntproc);
1736 /* determine which drives are fixed, for GetCachedVolumeInformation */
1738 /* GetDriveType must have trailing backslash. */
1739 char drive[] = "A:\\";
1741 /* Loop over all possible drive letters */
1742 while ( *drive <= 'Z' )
1744 /* Record if this drive letter refers to a fixed drive. */
1745 fixed_drives[ DRIVE_INDEX (*drive) ] =
1746 (GetDriveType (drive) == DRIVE_FIXED);
1754 tty_semi_canonicalize_console_connection (Lisp_Object connection,
1755 Error_behavior errb)
1761 tty_canonicalize_console_connection (Lisp_Object connection,
1762 Error_behavior errb)
1768 tty_semi_canonicalize_device_connection (Lisp_Object connection,
1769 Error_behavior errb)
1775 tty_canonicalize_device_connection (Lisp_Object connection,
1776 Error_behavior errb)
1782 /*--------------------------------------------------------------------*/
1783 /* Signal support */
1784 /*--------------------------------------------------------------------*/
1786 /* We need MS-defined signal and raise here */
1790 #define sigmask(nsig) (1U << nsig)
1792 /* We can support as many signals as fit into word */
1795 /* Signal handlers. Initial value = 0 = SIG_DFL */
1796 static void (__cdecl *signal_handlers[SIG_MAX])(int) = {0};
1798 /* Signal block mask: bit set to 1 means blocked */
1799 unsigned signal_block_mask = 0;
1801 /* Signal pending mask: bit set to 1 means sig is pending */
1802 unsigned signal_pending_mask = 0;
1804 msw_sighandler msw_sigset (int nsig, msw_sighandler handler)
1806 /* We delegate some signals to the system function */
1807 if (nsig == SIGFPE || nsig == SIGABRT || nsig == SIGINT)
1808 return signal (nsig, handler);
1810 if (nsig < 0 || nsig > SIG_MAX)
1816 /* Store handler ptr */
1818 msw_sighandler old_handler = signal_handlers[nsig];
1819 signal_handlers[nsig] = handler;
1824 int msw_sighold (int nsig)
1826 if (nsig < 0 || nsig > SIG_MAX)
1827 return errno = EINVAL;
1829 signal_block_mask |= sigmask(nsig);
1833 int msw_sigrelse (int nsig)
1835 if (nsig < 0 || nsig > SIG_MAX)
1836 return errno = EINVAL;
1838 signal_block_mask &= ~sigmask(nsig);
1840 if (signal_pending_mask & sigmask(nsig))
1846 int msw_sigpause (int nsig)
1848 /* This is currently not called, because the only
1849 call to sigpause inside XEmacs is with SIGCHLD
1850 parameter. Just in case, we put an assert here,
1851 so anyone who will add a call to sigpause will
1852 be surprised (or surprise someone else...) */
1857 int msw_raise (int nsig)
1859 /* We delegate some raises to the system routine */
1860 if (nsig == SIGFPE || nsig == SIGABRT || nsig == SIGINT)
1861 return raise (nsig);
1863 if (nsig < 0 || nsig > SIG_MAX)
1864 return errno = EINVAL;
1866 /* If the signal is blocked, remember to issue later */
1867 if (signal_block_mask & sigmask(nsig))
1869 signal_pending_mask |= sigmask(nsig);
1873 if (signal_handlers[nsig] == SIG_IGN)
1876 if (signal_handlers[nsig] != SIG_DFL)
1878 (*signal_handlers[nsig])(nsig);
1882 /* Default signal actions */
1883 if (nsig == SIGALRM || nsig == SIGPROF)
1886 /* Other signals are ignored by default */
1890 /*--------------------------------------------------------------------*/
1892 /*--------------------------------------------------------------------*/
1894 /* We emulate two timers, one for SIGALRM, another for SIGPROF.
1896 itimerproc() function has an implementation limitation: it does
1897 not allow to set *both* interval and period. If an attempt is
1898 made to set both, and then they are unequal, the function
1901 Minimum timer resolution on Win32 systems varies, and is greater
1902 than or equal than 1 ms. The resolution is always wrapped not to
1903 attempt to get below the system defined limit.
1906 /* Timer precision, denominator of one fraction: for 100 ms
1907 interval, request 10 ms precision
1909 const int timer_prec = 10;
1911 /* Last itimervals, as set by calls to setitimer */
1912 static struct itimerval it_alarm;
1913 static struct itimerval it_prof;
1915 /* Timer IDs as returned by MM */
1916 MMRESULT tid_alarm = 0;
1917 MMRESULT tid_prof = 0;
1919 static void CALLBACK timer_proc (UINT uID, UINT uMsg, DWORD dwUser,
1920 DWORD dw1, DWORD dw2)
1922 /* Just raise a signal indicated by dwUser parameter */
1926 /* Divide time in ms specified by IT by DENOM. Return 1 ms
1927 if division results in zero */
1928 static UINT period (const struct itimerval* it, UINT denom)
1930 static TIMECAPS time_caps;
1933 const struct timeval* tv =
1934 (it->it_value.tv_sec == 0 && it->it_value.tv_usec == 0)
1935 ? &it->it_interval : &it->it_value;
1937 /* Zero means stop timer */
1938 if (tv->tv_sec == 0 && tv->tv_usec == 0)
1941 /* Convert to ms and divide by denom */
1942 res = (tv->tv_sec * 1000 + (tv->tv_usec + 500) / 1000) / denom;
1944 /* Converge to minimum timer resolution */
1945 if (time_caps.wPeriodMin == 0)
1946 timeGetDevCaps (&time_caps, sizeof(time_caps));
1948 if (res < time_caps.wPeriodMin)
1949 res = time_caps.wPeriodMin;
1954 static int setitimer_helper (const struct itimerval* itnew,
1955 struct itimerval* itold, struct itimerval* itcurrent,
1956 MMRESULT* tid, DWORD sigkind)
1958 UINT delay, resolution, event_type;
1960 /* First stop the old timer */
1963 timeKillEvent (*tid);
1964 timeEndPeriod (period (itcurrent, timer_prec));
1968 /* Return old itimerval if requested */
1970 *itold = *itcurrent;
1972 *itcurrent = *itnew;
1974 /* Determine if to start new timer */
1975 delay = period (itnew, 1);
1978 resolution = period (itnew, timer_prec);
1979 event_type = (itnew->it_value.tv_sec == 0 && itnew->it_value.tv_usec == 0)
1980 ? TIME_ONESHOT : TIME_PERIODIC;
1981 timeBeginPeriod (resolution);
1982 *tid = timeSetEvent (delay, resolution, timer_proc, sigkind, event_type);
1985 return !delay || *tid;
1988 int setitimer (int kind, const struct itimerval* itnew,
1989 struct itimerval* itold)
1991 /* In this version, both interval and value are allowed
1992 only if they are equal. */
1993 assert ((itnew->it_value.tv_sec == 0 && itnew->it_value.tv_usec == 0)
1994 || (itnew->it_interval.tv_sec == 0 && itnew->it_interval.tv_usec == 0)
1995 || (itnew->it_value.tv_sec == itnew->it_interval.tv_sec &&
1996 itnew->it_value.tv_usec == itnew->it_interval.tv_usec));
1998 if (kind == ITIMER_REAL)
1999 return setitimer_helper (itnew, itold, &it_alarm, &tid_alarm, SIGALRM);
2000 else if (kind == ITIMER_PROF)
2001 return setitimer_helper (itnew, itold, &it_prof, &tid_prof, SIGPROF);
2003 return errno = EINVAL;
2007 /*--------------------------------------------------------------------*/
2008 /* Memory-mapped files */
2009 /*--------------------------------------------------------------------*/
2012 open_input_file (file_data *p_file, const char *filename)
2014 /* Synched with FSF 20.6. We fixed some warnings. */
2016 HANDLE file_mapping;
2018 DWORD size, upper_size;
2020 file = CreateFile (filename, GENERIC_READ, FILE_SHARE_READ, NULL,
2021 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
2022 if (file == INVALID_HANDLE_VALUE)
2025 size = GetFileSize (file, &upper_size);
2026 file_mapping = CreateFileMapping (file, NULL, PAGE_READONLY,
2031 file_base = MapViewOfFile (file_mapping, FILE_MAP_READ, 0, 0, size);
2035 p_file->name = (char *)filename;
2036 p_file->size = size;
2037 p_file->file = file;
2038 p_file->file_mapping = file_mapping;
2039 p_file->file_base = (char *)file_base;
2045 open_output_file (file_data *p_file, const char *filename, unsigned long size)
2047 /* Synched with FSF 20.6. We fixed some warnings. */
2049 HANDLE file_mapping;
2052 file = CreateFile (filename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
2053 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
2054 if (file == INVALID_HANDLE_VALUE)
2057 file_mapping = CreateFileMapping (file, NULL, PAGE_READWRITE,
2062 file_base = MapViewOfFile (file_mapping, FILE_MAP_WRITE, 0, 0, size);
2063 if (file_base == NULL)
2066 p_file->name = filename;
2067 p_file->size = size;
2068 p_file->file = file;
2069 p_file->file_mapping = file_mapping;
2070 p_file->file_base = (char*) file_base;
2075 #if 1 /* !defined(__MINGW32__) */
2076 /* Return pointer to section header for section containing the given
2077 relative virtual address. */
2078 static IMAGE_SECTION_HEADER *
2079 rva_to_section (DWORD rva, IMAGE_NT_HEADERS * nt_header)
2081 /* Synched with FSF 20.6. We added MINGW32 stuff. */
2082 PIMAGE_SECTION_HEADER section;
2085 section = IMAGE_FIRST_SECTION (nt_header);
2087 for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
2089 /* Some linkers (eg. the NT SDK linker I believe) swapped the
2090 meaning of these two values - or rather, they ignored
2091 VirtualSize entirely and always set it to zero. This affects
2092 some very old exes (eg. gzip dated Dec 1993). Since
2093 mswindows_executable_type relies on this function to work reliably,
2094 we need to cope with this. */
2095 DWORD real_size = max (section->SizeOfRawData,
2096 section->Misc.VirtualSize);
2097 if (rva >= section->VirtualAddress
2098 && rva < section->VirtualAddress + real_size)
2107 mswindows_executable_type (const char * filename, int * is_dos_app,
2108 int * is_cygnus_app)
2110 /* Synched with FSF 20.6. We added MINGW32 stuff and casts. */
2111 file_data executable;
2114 /* Default values in case we can't tell for sure. */
2115 *is_dos_app = FALSE;
2116 *is_cygnus_app = FALSE;
2118 if (!open_input_file (&executable, filename))
2121 p = strrchr (filename, '.');
2123 /* We can only identify DOS .com programs from the extension. */
2124 if (p && stricmp (p, ".com") == 0)
2126 else if (p && (stricmp (p, ".bat") == 0 ||
2127 stricmp (p, ".cmd") == 0))
2129 /* A DOS shell script - it appears that CreateProcess is happy to
2130 accept this (somewhat surprisingly); presumably it looks at
2131 COMSPEC to determine what executable to actually invoke.
2132 Therefore, we have to do the same here as well. */
2133 /* Actually, I think it uses the program association for that
2134 extension, which is defined in the registry. */
2135 p = egetenv ("COMSPEC");
2137 mswindows_executable_type (p, is_dos_app, is_cygnus_app);
2141 /* Look for DOS .exe signature - if found, we must also check that
2142 it isn't really a 16- or 32-bit Windows exe, since both formats
2143 start with a DOS program stub. Note that 16-bit Windows
2144 executables use the OS/2 1.x format. */
2146 #if 0 /* defined( __MINGW32__ ) */
2147 /* mingw32 doesn't have enough headers to detect cygwin
2148 apps, just do what we can. */
2149 FILHDR * exe_header;
2151 exe_header = (FILHDR*) executable.file_base;
2152 if (exe_header->e_magic != DOSMAGIC)
2155 if ((char*) exe_header->e_lfanew > (char*) executable.size)
2157 /* Some dos headers (pkunzip) have bogus e_lfanew fields. */
2160 else if (exe_header->nt_signature != NT_SIGNATURE)
2165 IMAGE_DOS_HEADER * dos_header;
2166 IMAGE_NT_HEADERS * nt_header;
2168 dos_header = (PIMAGE_DOS_HEADER) executable.file_base;
2169 if (dos_header->e_magic != IMAGE_DOS_SIGNATURE)
2172 nt_header = (PIMAGE_NT_HEADERS) ((char*) dos_header + dos_header->e_lfanew);
2174 if ((char*) nt_header > (char*) dos_header + executable.size)
2176 /* Some dos headers (pkunzip) have bogus e_lfanew fields. */
2179 else if (nt_header->Signature != IMAGE_NT_SIGNATURE &&
2180 LOWORD (nt_header->Signature) != IMAGE_OS2_SIGNATURE)
2184 else if (nt_header->Signature == IMAGE_NT_SIGNATURE)
2186 /* Look for cygwin.dll in DLL import list. */
2187 IMAGE_DATA_DIRECTORY import_dir =
2188 nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
2189 IMAGE_IMPORT_DESCRIPTOR * imports;
2190 IMAGE_SECTION_HEADER * section;
2192 section = rva_to_section (import_dir.VirtualAddress, nt_header);
2193 imports = (IMAGE_IMPORT_DESCRIPTOR *) RVA_TO_PTR (import_dir.VirtualAddress,
2194 section, executable);
2196 for ( ; imports->Name; imports++)
2198 char *dllname = (char*) RVA_TO_PTR (imports->Name, section, executable);
2200 /* The exact name of the cygwin dll has changed with
2201 various releases, but hopefully this will be reasonably
2203 if (strncmp (dllname, "cygwin", 6) == 0)
2205 *is_cygnus_app = TRUE;
2214 close_file_data (&executable);
2217 /* Close the system structures associated with the given file. */
2219 close_file_data (file_data *p_file)
2221 UnmapViewOfFile (p_file->file_base);
2222 CloseHandle (p_file->file_mapping);
2223 CloseHandle (p_file->file);
2229 DEFVAR_INT ("nt-fake-unix-uid", &nt_fake_unix_uid /*
2230 *Set uid returned by `user-uid' and `user-real-uid'.
2231 Under NT and 9x, there is no uids, and even no almighty user called root.
2232 By setting this variable, you can have any uid of choice. Default is 0.
2233 Changes to this variable take effect immediately.
2235 nt_fake_unix_uid = 0;