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;
51 Fixnum nt_fake_unix_uid;
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 getpwuid, getpwnam and others. */
74 #define PASSWD_FIELD_SIZE 256
76 static char the_passwd_name[PASSWD_FIELD_SIZE];
77 static char the_passwd_passwd[PASSWD_FIELD_SIZE];
78 static char the_passwd_gecos[PASSWD_FIELD_SIZE];
79 static char the_passwd_dir[PASSWD_FIELD_SIZE];
80 static char the_passwd_shell[PASSWD_FIELD_SIZE];
82 static struct passwd the_passwd =
97 return nt_fake_unix_uid;
103 return nt_fake_unix_uid;
109 return the_passwd.pw_gid;
121 if (uid == nt_fake_unix_uid)
123 the_passwd.pw_gid = the_passwd.pw_uid = uid;
131 getpwnam (const char *name)
135 pw = getpwuid (getuid ());
139 if (stricmp (name, pw->pw_name))
146 init_user_info (void)
148 /* This code is pretty much of ad hoc nature. There is no unix-like
149 UIDs under Windows NT. There is no concept of root user, because
150 all security is ACL-based. Instead, let's use a simple variable,
151 nt-fake-unix-uid, which would allow the user to have a uid of
152 choice. --kkm, 02/03/2000 */
154 /* Find the user's real name by opening the process token and
155 looking up the name associated with the user-sid in that token.
157 Use the relative portion of the identifier authority value from
158 the user-sid as the user id value (same for group id using the
159 primary group sid from the process token). */
161 char user_sid[256], name[256], domain[256];
162 DWORD length = sizeof (name), dlength = sizeof (domain), trash;
164 SID_NAME_USE user_type;
166 if (OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY, &token)
167 && GetTokenInformation (token, TokenUser,
168 (PVOID) user_sid, sizeof (user_sid), &trash)
169 && LookupAccountSid (NULL, *((PSID *) user_sid), name, &length,
170 domain, &dlength, &user_type))
172 strcpy (the_passwd.pw_name, name);
173 /* Determine a reasonable uid value. */
174 if (stricmp ("administrator", name) == 0)
176 the_passwd.pw_uid = 0;
177 the_passwd.pw_gid = 0;
181 SID_IDENTIFIER_AUTHORITY * pSIA;
183 pSIA = GetSidIdentifierAuthority (*((PSID *) user_sid));
184 /* I believe the relative portion is the last 4 bytes (of 6)
186 the_passwd.pw_uid = ((pSIA->Value[2] << 24) +
187 (pSIA->Value[3] << 16) +
188 (pSIA->Value[4] << 8) +
189 (pSIA->Value[5] << 0));
190 /* restrict to conventional uid range for normal users */
191 the_passwd.pw_uid = the_passwd.pw_uid % 60001;
194 if (GetTokenInformation (token, TokenPrimaryGroup,
195 (PVOID) user_sid, sizeof (user_sid), &trash))
197 SID_IDENTIFIER_AUTHORITY * pSIA;
199 pSIA = GetSidIdentifierAuthority (*((PSID *) user_sid));
200 the_passwd.pw_gid = ((pSIA->Value[2] << 24) +
201 (pSIA->Value[3] << 16) +
202 (pSIA->Value[4] << 8) +
203 (pSIA->Value[5] << 0));
204 /* I don't know if this is necessary, but for safety... */
205 the_passwd.pw_gid = the_passwd.pw_gid % 60001;
208 the_passwd.pw_gid = the_passwd.pw_uid;
211 /* If security calls are not supported (presumably because we
212 are running under Windows 95), fallback to this. */
213 else if (GetUserName (name, &length))
215 strcpy (the_passwd.pw_name, name);
216 if (stricmp ("administrator", name) == 0)
217 the_passwd.pw_uid = 0;
219 the_passwd.pw_uid = 123;
220 the_passwd.pw_gid = the_passwd.pw_uid;
224 strcpy (the_passwd.pw_name, "unknown");
225 the_passwd.pw_uid = 123;
226 the_passwd.pw_gid = 123;
232 /* Obtain only logon id here, uid part is moved to getuid */
234 DWORD length = sizeof (name);
235 if (GetUserName (name, &length))
236 strcpy (the_passwd.pw_name, name);
238 strcpy (the_passwd.pw_name, "unknown");
241 /* Ensure HOME and SHELL are defined. */
244 * With XEmacs, setting $HOME is deprecated.
246 if (getenv ("HOME") == NULL)
249 if (getenv ("SHELL") == NULL)
250 putenv ((GetVersion () & 0x80000000) ? "SHELL=command" : "SHELL=cmd");
252 /* Set dir and shell from environment variables. */
253 strcpy (the_passwd.pw_dir, (char *)get_home_directory());
254 strcpy (the_passwd.pw_shell, getenv ("SHELL"));
257 /* Normalize filename by converting all path separators to
258 the specified separator. Also conditionally convert upper
259 case path name components to lower case. */
262 normalize_filename (char *fp, char path_sep)
267 /* Always lower-case drive letters a-z, even if the filesystem
268 preserves case in filenames.
269 This is so filenames can be compared by string comparison
270 functions that are case-sensitive. Even case-preserving filesystems
271 do not distinguish case in drive letters. */
272 if (fp[1] == ':' && *fp >= 'A' && *fp <= 'Z')
278 if (NILP (Vmswindows_downcase_file_names))
282 if (*fp == '/' || *fp == '\\')
289 sep = path_sep; /* convert to this path separator */
290 elem = fp; /* start of current path element */
293 if (*fp >= 'a' && *fp <= 'z')
294 elem = 0; /* don't convert this element */
296 if (*fp == 0 || *fp == ':')
298 sep = *fp; /* restore current separator (or 0) */
299 *fp = '/'; /* after conversion of this element */
302 if (*fp == '/' || *fp == '\\')
304 if (elem && elem != fp)
306 *fp = 0; /* temporary end of string */
307 _strlwr (elem); /* while we convert to lower case */
309 *fp = sep; /* convert (or restore) path separator */
310 elem = fp + 1; /* next element starts after separator */
316 /* Destructively turn backslashes into slashes. */
318 dostounix_filename (char *p)
320 normalize_filename (p, '/');
323 /* Destructively turn slashes into backslashes. */
325 unixtodos_filename (char *p)
327 normalize_filename (p, '\\');
330 /* Remove all CR's that are followed by a LF.
331 (From msdos.c...probably should figure out a way to share it,
332 although this code isn't going to ever change.) */
334 crlf_to_lf (int n, unsigned char *buf, unsigned *lf_count)
336 unsigned char *np = buf;
337 unsigned char *startp = buf;
338 unsigned char *endp = buf + n;
342 while (buf < endp - 1)
348 if (*(++buf) != 0x0a)
363 /* Parse the root part of file name, if present. Return length and
364 optionally store pointer to char after root. */
366 parse_root (char * name, char ** pPath)
373 /* find the root name of the volume if given */
374 if (isalpha (name[0]) && name[1] == ':')
376 /* skip past drive specifier */
378 if (IS_DIRECTORY_SEP (name[0]))
381 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
387 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
392 if (IS_DIRECTORY_SEP (name[0]))
402 /* Get long base name for name; name is assumed to be absolute. */
404 get_long_basename (char * name, char * buf, int size)
406 WIN32_FIND_DATA find_data;
412 /* If the last component of NAME has a wildcard character,
413 return it as the basename. */
414 p = name + strlen (name);
415 while (*p != '\\' && *p != ':' && p > name) p--;
417 if (strchr (p, '*') || strchr (p, '?'))
419 if ((len = strlen (p)) < size)
420 memcpy (buf, p, len + 1);
427 dir_handle = FindFirstFile (name, &find_data);
428 if (dir_handle != INVALID_HANDLE_VALUE)
430 if ((len = strlen (find_data.cFileName)) < size)
431 memcpy (buf, find_data.cFileName, len + 1);
434 FindClose (dir_handle);
439 /* Get long name for file, if possible (assumed to be absolute). */
441 win32_get_long_filename (char * name, char * buf, int size)
446 char full[ MAX_PATH ];
453 /* Use local copy for destructive modification. */
454 memcpy (full, name, len+1);
455 unixtodos_filename (full);
457 /* Copy root part verbatim. */
458 len = parse_root (full, &p);
459 memcpy (o, full, len);
466 p = strchr (q, '\\');
468 len = get_long_basename (full, o, size);
486 while (p != NULL && *p);
492 /* Routines that are no-ops on NT but are defined to get Emacs to compile. */
494 #if 0 /* #### We do not need those, do we? -kkm */
496 unrequest_sigio (void)
508 #define REG_ROOT "SOFTWARE\\GNU\\XEmacs"
511 nt_get_resource (char *key, LPDWORD lpdwtype)
514 HKEY hrootkey = NULL;
517 /* Check both the current user and the local machine to see if
518 we have any resources. */
520 if (RegOpenKeyEx (HKEY_CURRENT_USER, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
524 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
525 && (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL
526 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
531 if (lpvalue) xfree (lpvalue);
533 RegCloseKey (hrootkey);
536 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
540 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS &&
541 (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL &&
542 RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
547 if (lpvalue) xfree (lpvalue);
549 RegCloseKey (hrootkey);
556 init_environment (void)
558 /* Check for environment variables and use registry if they don't exist */
564 static char * env_vars[] =
578 #if defined (HEAP_IN_DATA) && !defined(PDUMP)
579 cache_system_info ();
581 for (i = 0; i < countof (env_vars); i++)
583 if (!getenv (env_vars[i]) &&
584 (lpval = nt_get_resource (env_vars[i], &dwType)) != NULL)
586 if (dwType == REG_EXPAND_SZ)
588 char buf1[500], buf2[500];
590 ExpandEnvironmentStrings ((LPSTR) lpval, buf1, 500);
591 _snprintf (buf2, 499, "%s=%s", env_vars[i], buf1);
592 putenv (strdup (buf2));
594 else if (dwType == REG_SZ)
598 _snprintf (buf, 499, "%s=%s", env_vars[i], lpval);
599 putenv (strdup (buf));
607 /* Another special case: on NT, the PATH variable is actually named
608 "Path" although cmd.exe (perhaps NT itself) arranges for
609 environment variable lookup and setting to be case insensitive.
610 However, Emacs assumes a fully case sensitive environment, so we
611 need to change "Path" to "PATH" to match the expectations of
612 various elisp packages. We do this by the sneaky method of
613 modifying the string in the C runtime environ entry.
615 The same applies to COMSPEC. */
619 for (envp = environ; *envp; envp++)
620 if (_strnicmp (*envp, "PATH=", 5) == 0)
621 memcpy (*envp, "PATH=", 5);
622 else if (_strnicmp (*envp, "COMSPEC=", 8) == 0)
623 memcpy (*envp, "COMSPEC=", 8);
626 /* Remember the initial working directory for getwd, then make the
627 real wd be the location of emacs.exe to avoid conflicts when
628 renaming or deleting directories. (We also don't call chdir when
629 running subprocesses for the same reason.) */
630 if (!GetCurrentDirectory (MAXPATHLEN, startup_dir))
635 char modname[MAX_PATH];
637 if (!GetModuleFileName (NULL, modname, MAX_PATH))
639 if ((p = strrchr (modname, '\\')) == NULL)
643 SetCurrentDirectory (modname);
649 #ifndef HAVE_X_WINDOWS
650 /* X11R6 on NT provides the single parameter version of this command. */
652 #include <sys/timeb.h>
654 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
656 gettimeofday (struct timeval *tv, struct timezone *tz)
661 tv->tv_sec = tb.time;
662 tv->tv_usec = tb.millitm * 1000L;
665 tz->tz_minuteswest = tb.timezone; /* minutes west of Greenwich */
666 tz->tz_dsttime = tb.dstflag; /* type of dst correction */
670 #endif /* HAVE_X_WINDOWS */
672 /* ------------------------------------------------------------------------- */
673 /* IO support and wrapper functions for Win32 API. */
674 /* ------------------------------------------------------------------------- */
676 /* Place a wrapper around the MSVC version of ctime. It returns NULL
677 on network directories, so we handle that case here.
678 (Ulrich Leodolter, 1/11/95). */
680 sys_ctime (const time_t *t)
682 char *str = (char *) ctime (t);
683 return (str ? str : "Sun Jan 01 00:00:00 1970");
686 /* Emulate sleep...we could have done this with a define, but that
687 would necessitate including windows.h in the files that used it.
688 This is much easier. */
690 #ifndef HAVE_X_WINDOWS
692 sys_sleep (int seconds)
694 Sleep (seconds * 1000);
698 /* #### This is an evil dirty hack. We must get rid of it.
699 Word "munging" is not in XEmacs lexicon. - kkm */
701 /* Internal MSVC data and functions for low-level descriptor munging */
702 #if (_MSC_VER == 900)
703 extern char _osfile[];
705 extern int __cdecl _set_osfhnd (int fd, long h);
706 extern int __cdecl _free_osfhnd (int fd);
708 /* parallel array of private info on file handles */
709 filedesc fd_info [ MAXDESC ];
711 typedef struct volume_info_data {
712 struct volume_info_data * next;
714 /* time when info was obtained */
717 /* actual volume info */
726 /* Global referenced by various functions. */
727 static volume_info_data volume_info;
729 /* Vector to indicate which drives are local and fixed (for which cached
730 data never expires). */
731 static BOOL fixed_drives[26];
733 /* Consider cached volume information to be stale if older than 10s,
734 at least for non-local drives. Info for fixed drives is never stale. */
735 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
736 #define VOLINFO_STILL_VALID( root_dir, info ) \
737 ( ( isalpha (root_dir[0]) && \
738 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
739 || GetTickCount () - info->timestamp < 10000 )
741 /* Cache support functions. */
743 /* Simple linked list with linear search is sufficient. */
744 static volume_info_data *volume_cache = NULL;
746 static volume_info_data *
747 lookup_volume_info (char * root_dir)
749 volume_info_data * info;
751 for (info = volume_cache; info; info = info->next)
752 if (stricmp (info->root_dir, root_dir) == 0)
758 add_volume_info (char * root_dir, volume_info_data * info)
760 info->root_dir = xstrdup (root_dir);
761 info->next = volume_cache;
766 /* Wrapper for GetVolumeInformation, which uses caching to avoid
767 performance penalty (~2ms on 486 for local drives, 7.5ms for local
768 cdrom drive, ~5-10ms or more for remote drives on LAN). */
770 GetCachedVolumeInformation (char * root_dir)
772 volume_info_data * info;
773 char default_root[ MAX_PATH ];
775 /* NULL for root_dir means use root from current directory. */
776 if (root_dir == NULL)
778 if (GetCurrentDirectory (MAX_PATH, default_root) == 0)
780 parse_root (default_root, &root_dir);
782 root_dir = default_root;
785 /* Local fixed drives can be cached permanently. Removable drives
786 cannot be cached permanently, since the volume name and serial
787 number (if nothing else) can change. Remote drives should be
788 treated as if they are removable, since there is no sure way to
789 tell whether they are or not. Also, the UNC association of drive
790 letters mapped to remote volumes can be changed at any time (even
791 by other processes) without notice.
793 As a compromise, so we can benefit from caching info for remote
794 volumes, we use a simple expiry mechanism to invalidate cache
795 entries that are more than ten seconds old. */
798 /* No point doing this, because WNetGetConnection is even slower than
799 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
800 GetDriveType is about the only call of this type which does not
801 involve network access, and so is extremely quick). */
803 /* Map drive letter to UNC if remote. */
804 if ( isalpha( root_dir[0] ) && !fixed[ DRIVE_INDEX( root_dir[0] ) ] )
806 char remote_name[ 256 ];
807 char drive[3] = { root_dir[0], ':' };
809 if (WNetGetConnection (drive, remote_name, sizeof (remote_name))
815 info = lookup_volume_info (root_dir);
817 if (info == NULL || ! VOLINFO_STILL_VALID (root_dir, info))
825 /* Info is not cached, or is stale. */
826 if (!GetVolumeInformation (root_dir,
831 type, sizeof (type)))
834 /* Cache the volume information for future use, overwriting existing
838 info = (volume_info_data *) xmalloc (sizeof (volume_info_data));
839 add_volume_info (root_dir, info);
847 info->name = xstrdup (name);
848 info->serialnum = serialnum;
849 info->maxcomp = maxcomp;
851 info->type = xstrdup (type);
852 info->timestamp = GetTickCount ();
858 /* Get information on the volume where name is held; set path pointer to
859 start of pathname in name (past UNC header\volume header if present). */
861 get_volume_info (const char * name, const char ** pPath)
864 char *rootname = NULL; /* default to current volume */
865 volume_info_data * info;
870 /* find the root name of the volume if given */
871 if (isalpha (name[0]) && name[1] == ':')
879 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
886 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
899 info = GetCachedVolumeInformation (rootname);
902 /* Set global referenced by other functions. */
909 /* Determine if volume is FAT format (ie. only supports short 8.3
910 names); also set path pointer to start of pathname in name. */
912 is_fat_volume (const char * name, const char ** pPath)
914 if (get_volume_info (name, pPath))
915 return (volume_info.maxcomp == 12);
919 /* Map filename to a legal 8.3 name if necessary. */
921 map_win32_filename (const char * name, const char ** pPath)
923 static char shortname[MAX_PATH];
924 char * str = shortname;
927 const char * save_name = name;
929 if (is_fat_volume (name, &path)) /* truncate to 8.3 */
931 REGISTER int left = 8; /* maximum number of chars in part */
932 REGISTER int extn = 0; /* extension added? */
933 REGISTER int dots = 2; /* maximum number of dots allowed */
936 *str++ = *name++; /* skip past UNC header */
938 while ((c = *name++))
945 extn = 0; /* reset extension flags */
946 dots = 2; /* max 2 dots */
947 left = 8; /* max length 8 for main part */
951 extn = 0; /* reset extension flags */
952 dots = 2; /* max 2 dots */
953 left = 8; /* max length 8 for main part */
958 /* Convert path components of the form .xxx to _xxx,
959 but leave . and .. as they are. This allows .emacs
960 to be read as _emacs, for example. */
964 IS_DIRECTORY_SEP (*name))
979 extn = 1; /* we've got an extension */
980 left = 3; /* 3 chars in extension */
984 /* any embedded dots after the first are converted to _ */
989 case '#': /* don't lose these, they're important */
991 str[-1] = c; /* replace last character of part */
996 *str++ = tolower (c); /* map to lower case (looks nicer) */
998 dots = 0; /* started a path component */
1007 strcpy (shortname, name);
1008 unixtodos_filename (shortname);
1012 *pPath = shortname + (path - save_name);
1018 /* Emulate the Unix directory procedures opendir, closedir,
1019 and readdir. We can't use the procedures supplied in sysdep.c,
1020 so we provide them here. */
1022 struct direct dir_static; /* simulated directory contents */
1023 static HANDLE dir_find_handle = INVALID_HANDLE_VALUE;
1024 static int dir_is_fat;
1025 static char dir_pathname[MAXPATHLEN+1];
1026 static WIN32_FIND_DATA dir_find_data;
1029 opendir (const char *filename)
1033 /* Opening is done by FindFirstFile. However, a read is inherent to
1034 this operation, so we defer the open until read time. */
1036 if (!(dirp = xnew_and_zero(DIR)))
1038 if (dir_find_handle != INVALID_HANDLE_VALUE)
1045 strncpy (dir_pathname, map_win32_filename (filename, NULL), MAXPATHLEN);
1046 dir_pathname[MAXPATHLEN] = '\0';
1047 dir_is_fat = is_fat_volume (filename, NULL);
1053 closedir (DIR *dirp)
1057 /* If we have a find-handle open, close it. */
1058 if (dir_find_handle != INVALID_HANDLE_VALUE)
1060 retval = FindClose (dir_find_handle);
1061 dir_find_handle = INVALID_HANDLE_VALUE;
1073 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
1074 if (dir_find_handle == INVALID_HANDLE_VALUE)
1076 char filename[MAXNAMLEN + 3];
1079 strcpy (filename, dir_pathname);
1080 ln = strlen (filename) - 1;
1081 if (!IS_DIRECTORY_SEP (filename[ln]))
1082 strcat (filename, "\\");
1083 strcat (filename, "*");
1085 dir_find_handle = FindFirstFile (filename, &dir_find_data);
1087 if (dir_find_handle == INVALID_HANDLE_VALUE)
1092 if (!FindNextFile (dir_find_handle, &dir_find_data))
1096 /* Emacs never uses this value, so don't bother making it match
1097 value returned by xemacs_stat(). */
1098 dir_static.d_ino = 1;
1100 dir_static.d_reclen = sizeof (struct direct) - MAXNAMLEN + 3 +
1101 dir_static.d_namlen - dir_static.d_namlen % 4;
1103 dir_static.d_namlen = strlen (dir_find_data.cFileName);
1104 strcpy (dir_static.d_name, dir_find_data.cFileName);
1106 _strlwr (dir_static.d_name);
1107 else if (!NILP (Vmswindows_downcase_file_names))
1110 for (p = dir_static.d_name; *p; p++)
1111 if (*p >= 'a' && *p <= 'z')
1114 _strlwr (dir_static.d_name);
1121 /* #### Have to check if all that sad story about '95 is true - kkm */
1123 sys_rename (const char * oldname, const char * newname)
1125 char temp[MAX_PATH];
1128 /* MoveFile on Win95 doesn't correctly change the short file name
1129 alias in a number of circumstances (it is not easy to predict when
1130 just by looking at oldname and newname, unfortunately). In these
1131 cases, renaming through a temporary name avoids the problem.
1133 A second problem on Win95 is that renaming through a temp name when
1134 newname is uppercase fails (the final long name ends up in
1135 lowercase, although the short alias might be uppercase) UNLESS the
1136 long temp name is not 8.3.
1138 So, on Win95 we always rename through a temp name, and we make sure
1139 the temp name has a long extension to ensure correct renaming. */
1141 strcpy (temp, map_win32_filename (oldname, NULL));
1143 if (GetVersion () & 0x80000000)
1147 if (p = strrchr (temp, '\\'))
1151 /* Force temp name to require a manufactured 8.3 alias - this
1152 seems to make the second rename work properly. */
1153 strcpy (p, "_rename_temp.XXXXXX");
1155 if (rename (map_win32_filename (oldname, NULL), temp) < 0)
1159 /* Emulate Unix behavior - newname is deleted if it already exists
1160 (at least if it is a file; don't do this for directories).
1161 However, don't do this if we are just changing the case of the file
1162 name - we will end up deleting the file we are trying to rename! */
1163 newname = map_win32_filename (newname, NULL);
1165 /* TODO: Use GetInformationByHandle (on NT) to ensure newname and temp
1166 do not refer to the same file, eg. through share aliases. */
1167 if (stricmp (newname, temp) != 0
1168 && (attr = GetFileAttributes (newname)) != -1
1169 && (attr & FILE_ATTRIBUTE_DIRECTORY) == 0)
1171 _chmod (newname, 0666);
1175 return rename (temp, newname);
1179 static FILETIME utc_base_ft;
1180 static int init = 0;
1184 static long double utc_base;
1187 convert_time (FILETIME ft)
1193 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
1202 st.wMilliseconds = 0;
1204 SystemTimeToFileTime (&st, &utc_base_ft);
1205 utc_base = (long double) utc_base_ft.dwHighDateTime
1206 * 4096 * 1024 * 1024 + utc_base_ft.dwLowDateTime;
1210 if (CompareFileTime (&ft, &utc_base_ft) < 0)
1213 ret = (long double) ft.dwHighDateTime * 4096 * 1024 * 1024 + ft.dwLowDateTime;
1215 return (time_t) (ret * 1e-7);
1219 #if defined(MINGW) && CYGWIN_VERSION_DLL_MAJOR <= 21
1220 #define LowPart u.LowPart
1221 #define HighPart u.HighPart
1224 static LARGE_INTEGER utc_base_li;
1227 convert_time (FILETIME uft)
1234 TIME_ZONE_INFORMATION tzi;
1242 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
1251 st.wMilliseconds = 0;
1253 SystemTimeToFileTime (&st, &utc_base_ft);
1255 utc_base_li.LowPart = utc_base_ft.dwLowDateTime;
1256 utc_base_li.HighPart = utc_base_ft.dwHighDateTime;
1263 /* On a compiler that supports long integers, do it the easy way */
1264 lft.LowPart = uft.dwLowDateTime;
1265 lft.HighPart = uft.dwHighDateTime;
1266 ret = (time_t) ((lft.QuadPart - utc_base_li.QuadPart) / 10000000);
1270 /* Do it the hard way using mktime. */
1271 FileTimeToLocalFileTime(&uft, &ft);
1272 FileTimeToSystemTime (&ft, &st);
1273 tzid = GetTimeZoneInformation (&tzi);
1274 t.tm_year = st.wYear - 1900;
1275 t.tm_mon = st.wMonth - 1;
1276 t.tm_mday = st.wDay;
1277 t.tm_hour = st.wHour;
1278 t.tm_min = st.wMinute;
1279 t.tm_sec = st.wSecond;
1280 t.tm_isdst = (tzid == TIME_ZONE_ID_DAYLIGHT);
1281 /* st.wMilliseconds not applicable */
1293 #if defined(MINGW) && CYGWIN_VERSION_DLL_MAJOR <= 21
1299 /* in case we ever have need of this */
1301 convert_from_time_t (time_t time, FILETIME * pft)
1307 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
1316 st.wMilliseconds = 0;
1318 SystemTimeToFileTime (&st, &utc_base_ft);
1319 utc_base = (long double) utc_base_ft.dwHighDateTime
1320 * 4096 * 1024 * 1024 + utc_base_ft.dwLowDateTime;
1324 /* time in 100ns units since 1-Jan-1601 */
1325 tmp = (long double) time * 1e7 + utc_base;
1326 pft->dwHighDateTime = (DWORD) (tmp / (4096.0 * 1024 * 1024));
1327 pft->dwLowDateTime = (DWORD) (tmp - pft->dwHighDateTime);
1332 /* No reason to keep this; faking inode values either by hashing or even
1333 using the file index from GetInformationByHandle, is not perfect and
1334 so by default Emacs doesn't use the inode values on Windows.
1335 Instead, we now determine file-truename correctly (except for
1336 possible drive aliasing etc). */
1338 /* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
1340 hashval (const unsigned char * str)
1345 h = (h << 4) + *str++;
1351 /* Return the hash value of the canonical pathname, excluding the
1352 drive/UNC header, to get a hopefully unique inode number. */
1354 generate_inode_val (const char * name)
1356 char fullname[ MAX_PATH ];
1360 /* Get the truly canonical filename, if it exists. (Note: this
1361 doesn't resolve aliasing due to subst commands, or recognize hard
1363 if (!win32_get_long_filename ((char *)name, fullname, MAX_PATH))
1366 parse_root (fullname, &p);
1367 /* Normal Win32 filesystems are still case insensitive. */
1374 /* #### aichner@ecf.teradyne.com reported that with the library
1375 provided stat/fstat, (file-exist "d:\\tmp\\") =>> nil,
1376 (file-exist "d:\\tmp") =>> t, when d:\tmp exists. Whenever
1377 we opt to use non-encapsulated stat(), this should serve as
1378 a compatibility test. --kkm */
1380 /* Since stat is encapsulated on Windows NT, we need to encapsulate
1381 the equally broken fstat as well. FSFmacs also provides its own
1382 utime. Is that necessary here too? */
1384 mswindows_fstat (int desc, struct stat * buf)
1386 HANDLE fh = (HANDLE) _get_osfhandle (desc);
1387 BY_HANDLE_FILE_INFORMATION info;
1391 switch (GetFileType (fh) & ~FILE_TYPE_REMOTE)
1393 case FILE_TYPE_DISK:
1394 buf->st_mode = _S_IFREG;
1395 if (!GetFileInformationByHandle (fh, &info))
1401 case FILE_TYPE_PIPE:
1402 buf->st_mode = _S_IFIFO;
1404 case FILE_TYPE_CHAR:
1405 case FILE_TYPE_UNKNOWN:
1407 buf->st_mode = _S_IFCHR;
1409 memset (&info, 0, sizeof (info));
1410 info.dwFileAttributes = 0;
1411 info.ftCreationTime = utc_base_ft;
1412 info.ftLastAccessTime = utc_base_ft;
1413 info.ftLastWriteTime = utc_base_ft;
1416 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1418 buf->st_mode = _S_IFDIR;
1419 buf->st_nlink = 2; /* doesn't really matter */
1420 fake_inode = 0; /* this doesn't either I think */
1424 buf->st_nlink = (short) info.nNumberOfLinks;
1425 /* Might as well use file index to fake inode values, but this
1426 is not guaranteed to be unique unless we keep a handle open
1427 all the time (even then there are situations where it is
1428 not unique). Reputedly, there are at most 48 bits of info
1429 (on NTFS, presumably less on FAT). */
1430 fake_inode = info.nFileIndexLow ^ info.nFileIndexHigh;
1433 /* MSVC defines _ino_t to be short; other libc's might not. */
1434 if (sizeof (buf->st_ino) == 2)
1435 buf->st_ino = (unsigned short) (fake_inode ^ (fake_inode >> 16));
1437 buf->st_ino = (unsigned short) fake_inode;
1439 /* consider files to belong to current user */
1443 buf->st_dev = info.dwVolumeSerialNumber;
1444 buf->st_rdev = info.dwVolumeSerialNumber;
1446 buf->st_size = info.nFileSizeLow;
1448 /* Convert timestamps to Unix format. */
1449 buf->st_mtime = convert_time (info.ftLastWriteTime);
1450 buf->st_atime = convert_time (info.ftLastAccessTime);
1451 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
1452 buf->st_ctime = convert_time (info.ftCreationTime);
1453 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
1455 /* determine rwx permissions */
1456 if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
1457 permission = _S_IREAD;
1459 permission = _S_IREAD | _S_IWRITE;
1461 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1462 permission |= _S_IEXEC;
1464 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
1469 /* MSVC stat function can't cope with UNC names and has other bugs, so
1470 replace it with our own. This also allows us to calculate consistent
1471 inode values without hacks in the main Emacs code. */
1473 mswindows_stat (const char * path, struct stat * buf)
1476 WIN32_FIND_DATA wfd;
1481 int rootdir = FALSE;
1483 if (path == NULL || buf == NULL)
1489 name = (char *) map_win32_filename (path, &path);
1490 /* must be valid filename, no wild cards */
1491 if (strchr (name, '*') || strchr (name, '?'))
1497 /* Remove trailing directory separator, unless name is the root
1498 directory of a drive or UNC volume in which case ensure there
1499 is a trailing separator. */
1500 len = strlen (name);
1501 rootdir = (path >= name + len - 1
1502 && (IS_DIRECTORY_SEP (*path) || *path == 0));
1503 name = strcpy ((char *)alloca (len + 2), name);
1507 if (!IS_DIRECTORY_SEP (name[len-1]))
1508 strcat (name, "\\");
1509 if (GetDriveType (name) < 2)
1514 memset (&wfd, 0, sizeof (wfd));
1515 wfd.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
1516 wfd.ftCreationTime = utc_base_ft;
1517 wfd.ftLastAccessTime = utc_base_ft;
1518 wfd.ftLastWriteTime = utc_base_ft;
1519 strcpy (wfd.cFileName, name);
1523 if (IS_DIRECTORY_SEP (name[len-1]))
1526 /* (This is hacky, but helps when doing file completions on
1527 network drives.) Optimize by using information available from
1528 active readdir if possible. */
1529 if (dir_find_handle != INVALID_HANDLE_VALUE &&
1530 (len = strlen (dir_pathname)),
1531 strnicmp (name, dir_pathname, len) == 0 &&
1532 IS_DIRECTORY_SEP (name[len]) &&
1533 stricmp (name + len + 1, dir_static.d_name) == 0)
1535 /* This was the last entry returned by readdir. */
1536 wfd = dir_find_data;
1540 fh = FindFirstFile (name, &wfd);
1541 if (fh == INVALID_HANDLE_VALUE)
1550 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1552 buf->st_mode = _S_IFDIR;
1553 buf->st_nlink = 2; /* doesn't really matter */
1554 fake_inode = 0; /* this doesn't either I think */
1556 else if (!NILP (Vmswindows_get_true_file_attributes))
1558 /* This is more accurate in terms of getting the correct number
1559 of links, but is quite slow (it is noticeable when Emacs is
1560 making a list of file name completions). */
1561 BY_HANDLE_FILE_INFORMATION info;
1563 /* No access rights required to get info. */
1564 fh = CreateFile (name, 0, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
1565 OPEN_EXISTING, 0, NULL);
1567 if (GetFileInformationByHandle (fh, &info))
1569 switch (GetFileType (fh))
1571 case FILE_TYPE_DISK:
1572 buf->st_mode = _S_IFREG;
1574 case FILE_TYPE_PIPE:
1575 buf->st_mode = _S_IFIFO;
1577 case FILE_TYPE_CHAR:
1578 case FILE_TYPE_UNKNOWN:
1580 buf->st_mode = _S_IFCHR;
1582 buf->st_nlink = (short) info.nNumberOfLinks;
1583 /* Might as well use file index to fake inode values, but this
1584 is not guaranteed to be unique unless we keep a handle open
1585 all the time (even then there are situations where it is
1586 not unique). Reputedly, there are at most 48 bits of info
1587 (on NTFS, presumably less on FAT). */
1588 fake_inode = info.nFileIndexLow ^ info.nFileIndexHigh;
1599 /* Don't bother to make this information more accurate. */
1600 buf->st_mode = _S_IFREG;
1606 /* Not sure if there is any point in this. */
1607 if (!NILP (Vwin32_generate_fake_inodes))
1608 fake_inode = generate_inode_val (name);
1609 else if (fake_inode == 0)
1611 /* For want of something better, try to make everything unique. */
1612 static DWORD gen_num = 0;
1613 fake_inode = ++gen_num;
1617 /* #### MSVC defines _ino_t to be short; other libc's might not. */
1618 buf->st_ino = (unsigned short) (fake_inode ^ (fake_inode >> 16));
1620 /* consider files to belong to current user */
1621 buf->st_uid = buf->st_gid = (short) nt_fake_unix_uid;
1623 /* volume_info is set indirectly by map_win32_filename */
1624 buf->st_dev = volume_info.serialnum;
1625 buf->st_rdev = volume_info.serialnum;
1627 buf->st_size = wfd.nFileSizeLow;
1629 /* Convert timestamps to Unix format. */
1630 buf->st_mtime = convert_time (wfd.ftLastWriteTime);
1631 buf->st_atime = convert_time (wfd.ftLastAccessTime);
1632 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
1633 buf->st_ctime = convert_time (wfd.ftCreationTime);
1634 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
1636 /* determine rwx permissions */
1637 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
1638 permission = _S_IREAD;
1640 permission = _S_IREAD | _S_IWRITE;
1642 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1643 permission |= _S_IEXEC;
1646 char * p = strrchr (name, '.');
1648 (stricmp (p, ".exe") == 0 ||
1649 stricmp (p, ".com") == 0 ||
1650 stricmp (p, ".bat") == 0 ||
1651 stricmp (p, ".cmd") == 0))
1652 permission |= _S_IEXEC;
1655 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
1660 /* From callproc.c */
1661 extern Lisp_Object Vbinary_process_input;
1662 extern Lisp_Object Vbinary_process_output;
1664 /* Unix pipe() has only one arg */
1666 sys_pipe (int * phandles)
1671 /* make pipe handles non-inheritable; when we spawn a child, we
1672 replace the relevant handle with an inheritable one. Also put
1673 pipes into binary mode; we will do text mode translation ourselves
1675 rc = _pipe (phandles, 0, _O_NOINHERIT | _O_BINARY);
1679 flags = FILE_PIPE | FILE_READ;
1680 if (!NILP (Vbinary_process_output))
1681 flags |= FILE_BINARY;
1682 fd_info[phandles[0]].flags = flags;
1684 flags = FILE_PIPE | FILE_WRITE;
1685 if (!NILP (Vbinary_process_input))
1686 flags |= FILE_BINARY;
1687 fd_info[phandles[1]].flags = flags;
1694 term_ntproc (int unused)
1701 /* Initial preparation for subprocess support: replace our standard
1702 handles with non-inheritable versions. */
1705 HANDLE stdin_save = INVALID_HANDLE_VALUE;
1706 HANDLE stdout_save = INVALID_HANDLE_VALUE;
1707 HANDLE stderr_save = INVALID_HANDLE_VALUE;
1709 parent = GetCurrentProcess ();
1711 /* ignore errors when duplicating and closing; typically the
1712 handles will be invalid when running as a gui program. */
1713 DuplicateHandle (parent,
1714 GetStdHandle (STD_INPUT_HANDLE),
1719 DUPLICATE_SAME_ACCESS);
1721 DuplicateHandle (parent,
1722 GetStdHandle (STD_OUTPUT_HANDLE),
1727 DUPLICATE_SAME_ACCESS);
1729 DuplicateHandle (parent,
1730 GetStdHandle (STD_ERROR_HANDLE),
1735 DUPLICATE_SAME_ACCESS);
1741 if (stdin_save != INVALID_HANDLE_VALUE)
1742 _open_osfhandle ((long) stdin_save, O_TEXT);
1744 _open ("nul", O_TEXT | O_NOINHERIT | O_RDONLY);
1747 if (stdout_save != INVALID_HANDLE_VALUE)
1748 _open_osfhandle ((long) stdout_save, O_TEXT);
1750 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
1753 if (stderr_save != INVALID_HANDLE_VALUE)
1754 _open_osfhandle ((long) stderr_save, O_TEXT);
1756 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
1760 /* unfortunately, atexit depends on implementation of malloc */
1761 /* atexit (term_ntproc); */
1762 signal (SIGABRT, term_ntproc);
1764 /* determine which drives are fixed, for GetCachedVolumeInformation */
1766 /* GetDriveType must have trailing backslash. */
1767 char drive[] = "A:\\";
1769 /* Loop over all possible drive letters */
1770 while ( *drive <= 'Z' )
1772 /* Record if this drive letter refers to a fixed drive. */
1773 fixed_drives[ DRIVE_INDEX (*drive) ] =
1774 (GetDriveType (drive) == DRIVE_FIXED);
1782 tty_semi_canonicalize_console_connection (Lisp_Object connection,
1783 Error_behavior errb)
1789 tty_canonicalize_console_connection (Lisp_Object connection,
1790 Error_behavior errb)
1796 tty_semi_canonicalize_device_connection (Lisp_Object connection,
1797 Error_behavior errb)
1803 tty_canonicalize_device_connection (Lisp_Object connection,
1804 Error_behavior errb)
1810 /*--------------------------------------------------------------------*/
1811 /* Signal support */
1812 /*--------------------------------------------------------------------*/
1814 /* We need MS-defined signal and raise here */
1818 #define sigmask(nsig) (1U << nsig)
1820 /* We can support as many signals as fit into word */
1823 /* Signal handlers. Initial value = 0 = SIG_DFL */
1824 static void (__cdecl *signal_handlers[SIG_MAX])(int) = {0};
1826 /* Signal block mask: bit set to 1 means blocked */
1827 unsigned signal_block_mask = 0;
1829 /* Signal pending mask: bit set to 1 means sig is pending */
1830 unsigned signal_pending_mask = 0;
1832 mswindows_sighandler mswindows_sigset (int nsig, mswindows_sighandler handler)
1834 /* We delegate some signals to the system function */
1835 if (nsig == SIGFPE || nsig == SIGABRT || nsig == SIGINT)
1836 return signal (nsig, handler);
1838 if (nsig < 0 || nsig > SIG_MAX)
1844 /* Store handler ptr */
1846 mswindows_sighandler old_handler = signal_handlers[nsig];
1847 signal_handlers[nsig] = handler;
1852 int mswindows_sighold (int nsig)
1854 if (nsig < 0 || nsig > SIG_MAX)
1855 return errno = EINVAL;
1857 signal_block_mask |= sigmask(nsig);
1861 int mswindows_sigrelse (int nsig)
1863 if (nsig < 0 || nsig > SIG_MAX)
1864 return errno = EINVAL;
1866 signal_block_mask &= ~sigmask(nsig);
1868 if (signal_pending_mask & sigmask(nsig))
1869 mswindows_raise (nsig);
1874 int mswindows_sigpause (int nsig)
1876 /* This is currently not called, because the only
1877 call to sigpause inside XEmacs is with SIGCHLD
1878 parameter. Just in case, we put an assert here,
1879 so anyone who will add a call to sigpause will
1880 be surprised (or surprise someone else...) */
1885 int mswindows_raise (int nsig)
1887 /* We delegate some raises to the system routine */
1888 if (nsig == SIGFPE || nsig == SIGABRT || nsig == SIGINT)
1889 return raise (nsig);
1891 if (nsig < 0 || nsig > SIG_MAX)
1892 return errno = EINVAL;
1894 /* If the signal is blocked, remember to issue later */
1895 if (signal_block_mask & sigmask(nsig))
1897 signal_pending_mask |= sigmask(nsig);
1901 if (signal_handlers[nsig] == SIG_IGN)
1904 if (signal_handlers[nsig] != SIG_DFL)
1906 (*signal_handlers[nsig])(nsig);
1910 /* Default signal actions */
1911 if (nsig == SIGALRM || nsig == SIGPROF)
1914 /* Other signals are ignored by default */
1918 /*--------------------------------------------------------------------*/
1920 /*--------------------------------------------------------------------*/
1922 /* We emulate two timers, one for SIGALRM, another for SIGPROF.
1924 itimerproc() function has an implementation limitation: it does
1925 not allow to set *both* interval and period. If an attempt is
1926 made to set both, and then they are unequal, the function
1929 Minimum timer resolution on Win32 systems varies, and is greater
1930 than or equal than 1 ms. The resolution is always wrapped not to
1931 attempt to get below the system defined limit.
1934 /* Timer precision, denominator of one fraction: for 100 ms
1935 interval, request 10 ms precision
1937 const int timer_prec = 10;
1939 /* Last itimervals, as set by calls to setitimer */
1940 static struct itimerval it_alarm;
1941 static struct itimerval it_prof;
1943 /* Timer IDs as returned by MM */
1944 MMRESULT tid_alarm = 0;
1945 MMRESULT tid_prof = 0;
1947 static void CALLBACK timer_proc (UINT uID, UINT uMsg, DWORD dwUser,
1948 DWORD dw1, DWORD dw2)
1950 /* Just raise a signal indicated by dwUser parameter */
1951 mswindows_raise (dwUser);
1954 /* Divide time in ms specified by IT by DENOM. Return 1 ms
1955 if division results in zero */
1956 static UINT period (const struct itimerval* it, UINT denom)
1958 static TIMECAPS time_caps;
1961 const struct timeval* tv =
1962 (it->it_value.tv_sec == 0 && it->it_value.tv_usec == 0)
1963 ? &it->it_interval : &it->it_value;
1965 /* Zero means stop timer */
1966 if (tv->tv_sec == 0 && tv->tv_usec == 0)
1969 /* Convert to ms and divide by denom */
1970 res = (tv->tv_sec * 1000 + (tv->tv_usec + 500) / 1000) / denom;
1972 /* Converge to minimum timer resolution */
1973 if (time_caps.wPeriodMin == 0)
1974 timeGetDevCaps (&time_caps, sizeof(time_caps));
1976 if (res < time_caps.wPeriodMin)
1977 res = time_caps.wPeriodMin;
1982 static int setitimer_helper (const struct itimerval* itnew,
1983 struct itimerval* itold, struct itimerval* itcurrent,
1984 MMRESULT* tid, DWORD sigkind)
1986 UINT delay, resolution, event_type;
1988 /* First stop the old timer */
1991 timeKillEvent (*tid);
1992 timeEndPeriod (period (itcurrent, timer_prec));
1996 /* Return old itimerval if requested */
1998 *itold = *itcurrent;
2000 *itcurrent = *itnew;
2002 /* Determine if to start new timer */
2003 delay = period (itnew, 1);
2006 resolution = period (itnew, timer_prec);
2007 event_type = (itnew->it_value.tv_sec == 0 && itnew->it_value.tv_usec == 0)
2008 ? TIME_ONESHOT : TIME_PERIODIC;
2009 timeBeginPeriod (resolution);
2010 *tid = timeSetEvent (delay, resolution, timer_proc, sigkind, event_type);
2013 return !delay || *tid;
2016 int setitimer (int kind, const struct itimerval* itnew,
2017 struct itimerval* itold)
2019 /* In this version, both interval and value are allowed
2020 only if they are equal. */
2021 assert ((itnew->it_value.tv_sec == 0 && itnew->it_value.tv_usec == 0)
2022 || (itnew->it_interval.tv_sec == 0 && itnew->it_interval.tv_usec == 0)
2023 || (itnew->it_value.tv_sec == itnew->it_interval.tv_sec &&
2024 itnew->it_value.tv_usec == itnew->it_interval.tv_usec));
2026 if (kind == ITIMER_REAL)
2027 return setitimer_helper (itnew, itold, &it_alarm, &tid_alarm, SIGALRM);
2028 else if (kind == ITIMER_PROF)
2029 return setitimer_helper (itnew, itold, &it_prof, &tid_prof, SIGPROF);
2031 return errno = EINVAL;
2035 /*--------------------------------------------------------------------*/
2036 /* Memory-mapped files */
2037 /*--------------------------------------------------------------------*/
2040 open_input_file (file_data *p_file, const char *filename)
2042 /* Synched with FSF 20.6. We fixed some warnings. */
2044 HANDLE file_mapping;
2046 DWORD size, upper_size;
2048 file = CreateFile (filename, GENERIC_READ, FILE_SHARE_READ, NULL,
2049 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
2050 if (file == INVALID_HANDLE_VALUE)
2053 size = GetFileSize (file, &upper_size);
2054 file_mapping = CreateFileMapping (file, NULL, PAGE_READONLY,
2059 file_base = MapViewOfFile (file_mapping, FILE_MAP_READ, 0, 0, size);
2063 p_file->name = (char *)filename;
2064 p_file->size = size;
2065 p_file->file = file;
2066 p_file->file_mapping = file_mapping;
2067 p_file->file_base = (char *)file_base;
2073 open_output_file (file_data *p_file, const char *filename, unsigned long size)
2075 /* Synched with FSF 20.6. We fixed some warnings. */
2077 HANDLE file_mapping;
2080 file = CreateFile (filename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
2081 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
2082 if (file == INVALID_HANDLE_VALUE)
2085 file_mapping = CreateFileMapping (file, NULL, PAGE_READWRITE,
2090 file_base = MapViewOfFile (file_mapping, FILE_MAP_WRITE, 0, 0, size);
2091 if (file_base == NULL)
2094 p_file->name = filename;
2095 p_file->size = size;
2096 p_file->file = file;
2097 p_file->file_mapping = file_mapping;
2098 p_file->file_base = (char*) file_base;
2103 #if 1 /* !defined(MINGW) */
2104 /* Return pointer to section header for section containing the given
2105 relative virtual address. */
2106 static IMAGE_SECTION_HEADER *
2107 rva_to_section (DWORD rva, IMAGE_NT_HEADERS * nt_header)
2109 /* Synched with FSF 20.6. We added MINGW stuff. */
2110 PIMAGE_SECTION_HEADER section;
2113 section = IMAGE_FIRST_SECTION (nt_header);
2115 for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
2117 /* Some linkers (eg. the NT SDK linker I believe) swapped the
2118 meaning of these two values - or rather, they ignored
2119 VirtualSize entirely and always set it to zero. This affects
2120 some very old exes (eg. gzip dated Dec 1993). Since
2121 mswindows_executable_type relies on this function to work reliably,
2122 we need to cope with this. */
2123 DWORD real_size = max (section->SizeOfRawData,
2124 section->Misc.VirtualSize);
2125 if (rva >= section->VirtualAddress
2126 && rva < section->VirtualAddress + real_size)
2135 mswindows_executable_type (const char * filename, int * is_dos_app,
2136 int * is_cygnus_app)
2138 /* Synched with FSF 20.6. We added MINGW stuff and casts. */
2139 file_data executable;
2142 /* Default values in case we can't tell for sure. */
2143 *is_dos_app = FALSE;
2144 *is_cygnus_app = FALSE;
2146 if (!open_input_file (&executable, filename))
2149 p = strrchr (filename, '.');
2151 /* We can only identify DOS .com programs from the extension. */
2152 if (p && stricmp (p, ".com") == 0)
2154 else if (p && (stricmp (p, ".bat") == 0 ||
2155 stricmp (p, ".cmd") == 0))
2157 /* A DOS shell script - it appears that CreateProcess is happy to
2158 accept this (somewhat surprisingly); presumably it looks at
2159 COMSPEC to determine what executable to actually invoke.
2160 Therefore, we have to do the same here as well. */
2161 /* Actually, I think it uses the program association for that
2162 extension, which is defined in the registry. */
2163 p = egetenv ("COMSPEC");
2165 mswindows_executable_type (p, is_dos_app, is_cygnus_app);
2169 /* Look for DOS .exe signature - if found, we must also check that
2170 it isn't really a 16- or 32-bit Windows exe, since both formats
2171 start with a DOS program stub. Note that 16-bit Windows
2172 executables use the OS/2 1.x format. */
2174 #if 0 /* defined( MINGW ) */
2175 /* mingw32 doesn't have enough headers to detect cygwin
2176 apps, just do what we can. */
2177 FILHDR * exe_header;
2179 exe_header = (FILHDR*) executable.file_base;
2180 if (exe_header->e_magic != DOSMAGIC)
2183 if ((char*) exe_header->e_lfanew > (char*) executable.size)
2185 /* Some dos headers (pkunzip) have bogus e_lfanew fields. */
2188 else if (exe_header->nt_signature != NT_SIGNATURE)
2193 IMAGE_DOS_HEADER * dos_header;
2194 IMAGE_NT_HEADERS * nt_header;
2196 dos_header = (PIMAGE_DOS_HEADER) executable.file_base;
2197 if (dos_header->e_magic != IMAGE_DOS_SIGNATURE)
2200 nt_header = (PIMAGE_NT_HEADERS) ((char*) dos_header + dos_header->e_lfanew);
2202 if ((char*) nt_header > (char*) dos_header + executable.size)
2204 /* Some dos headers (pkunzip) have bogus e_lfanew fields. */
2207 else if (nt_header->Signature != IMAGE_NT_SIGNATURE &&
2208 LOWORD (nt_header->Signature) != IMAGE_OS2_SIGNATURE)
2212 else if (nt_header->Signature == IMAGE_NT_SIGNATURE)
2214 /* Look for cygwin.dll in DLL import list. */
2215 IMAGE_DATA_DIRECTORY import_dir =
2216 nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
2217 IMAGE_IMPORT_DESCRIPTOR * imports;
2218 IMAGE_SECTION_HEADER * section;
2220 section = rva_to_section (import_dir.VirtualAddress, nt_header);
2221 imports = (IMAGE_IMPORT_DESCRIPTOR *) RVA_TO_PTR (import_dir.VirtualAddress,
2222 section, executable);
2224 for ( ; imports->Name; imports++)
2226 char *dllname = (char*) RVA_TO_PTR (imports->Name, section, executable);
2228 /* The exact name of the cygwin dll has changed with
2229 various releases, but hopefully this will be reasonably
2231 if (strncmp (dllname, "cygwin", 6) == 0)
2233 *is_cygnus_app = TRUE;
2242 close_file_data (&executable);
2245 /* Close the system structures associated with the given file. */
2247 close_file_data (file_data *p_file)
2249 UnmapViewOfFile (p_file->file_base);
2250 CloseHandle (p_file->file_mapping);
2251 CloseHandle (p_file->file);
2257 DEFVAR_INT ("nt-fake-unix-uid", &nt_fake_unix_uid /*
2258 *Set uid returned by `user-uid' and `user-real-uid'.
2259 Under NT and 9x, there is no uids, and even no almighty user called root.
2260 By setting this variable, you can have any uid of choice. Default is 0.
2261 Changes to this variable take effect immediately.
2263 nt_fake_unix_uid = 0;