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> */
34 #include "syssignal.h"
40 #include "syswindows.h"
46 extern Lisp_Object Vmswindows_downcase_file_names;
48 extern Lisp_Object Vwin32_generate_fake_inodes;
50 extern Lisp_Object Vmswindows_get_true_file_attributes;
52 Fixnum nt_fake_unix_uid;
54 static char startup_dir[ MAXPATHLEN ];
56 /* Get the current working directory. */
61 if (GetCurrentDirectory (MAXPATHLEN, dir) > 0)
65 /* Emacs doesn't actually change directory itself, and we want to
66 force our real wd to be where emacs.exe is to avoid unnecessary
67 conflicts when trying to rename or delete directories. */
68 strcpy (dir, startup_dir);
73 /* Emulate getpwuid, getpwnam and others. */
75 #define PASSWD_FIELD_SIZE 256
77 static char the_passwd_name[PASSWD_FIELD_SIZE];
78 static char the_passwd_passwd[PASSWD_FIELD_SIZE];
79 static char the_passwd_gecos[PASSWD_FIELD_SIZE];
80 static char the_passwd_dir[PASSWD_FIELD_SIZE];
81 static char the_passwd_shell[PASSWD_FIELD_SIZE];
83 static struct passwd the_passwd =
98 return nt_fake_unix_uid;
104 return nt_fake_unix_uid;
110 return the_passwd.pw_gid;
122 if (uid == nt_fake_unix_uid)
124 the_passwd.pw_gid = the_passwd.pw_uid = uid;
132 getpwnam (const char *name)
136 pw = getpwuid (getuid ());
140 if (stricmp (name, pw->pw_name))
147 init_user_info (void)
149 /* This code is pretty much of ad hoc nature. There is no unix-like
150 UIDs under Windows NT. There is no concept of root user, because
151 all security is ACL-based. Instead, let's use a simple variable,
152 nt-fake-unix-uid, which would allow the user to have a uid of
153 choice. --kkm, 02/03/2000 */
155 /* Find the user's real name by opening the process token and
156 looking up the name associated with the user-sid in that token.
158 Use the relative portion of the identifier authority value from
159 the user-sid as the user id value (same for group id using the
160 primary group sid from the process token). */
162 char user_sid[256], name[256], domain[256];
163 DWORD length = sizeof (name), dlength = sizeof (domain), trash;
165 SID_NAME_USE user_type;
167 if (OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY, &token)
168 && GetTokenInformation (token, TokenUser,
169 (PVOID) user_sid, sizeof (user_sid), &trash)
170 && LookupAccountSid (NULL, *((PSID *) user_sid), name, &length,
171 domain, &dlength, &user_type))
173 strcpy (the_passwd.pw_name, name);
174 /* Determine a reasonable uid value. */
175 if (stricmp ("administrator", name) == 0)
177 the_passwd.pw_uid = 0;
178 the_passwd.pw_gid = 0;
182 SID_IDENTIFIER_AUTHORITY * pSIA;
184 pSIA = GetSidIdentifierAuthority (*((PSID *) user_sid));
185 /* I believe the relative portion is the last 4 bytes (of 6)
187 the_passwd.pw_uid = ((pSIA->Value[2] << 24) +
188 (pSIA->Value[3] << 16) +
189 (pSIA->Value[4] << 8) +
190 (pSIA->Value[5] << 0));
191 /* restrict to conventional uid range for normal users */
192 the_passwd.pw_uid = the_passwd.pw_uid % 60001;
195 if (GetTokenInformation (token, TokenPrimaryGroup,
196 (PVOID) user_sid, sizeof (user_sid), &trash))
198 SID_IDENTIFIER_AUTHORITY * pSIA;
200 pSIA = GetSidIdentifierAuthority (*((PSID *) user_sid));
201 the_passwd.pw_gid = ((pSIA->Value[2] << 24) +
202 (pSIA->Value[3] << 16) +
203 (pSIA->Value[4] << 8) +
204 (pSIA->Value[5] << 0));
205 /* I don't know if this is necessary, but for safety... */
206 the_passwd.pw_gid = the_passwd.pw_gid % 60001;
209 the_passwd.pw_gid = the_passwd.pw_uid;
212 /* If security calls are not supported (presumably because we
213 are running under Windows 95), fallback to this. */
214 else if (GetUserName (name, &length))
216 strcpy (the_passwd.pw_name, name);
217 if (stricmp ("administrator", name) == 0)
218 the_passwd.pw_uid = 0;
220 the_passwd.pw_uid = 123;
221 the_passwd.pw_gid = the_passwd.pw_uid;
225 strcpy (the_passwd.pw_name, "unknown");
226 the_passwd.pw_uid = 123;
227 the_passwd.pw_gid = 123;
233 /* Obtain only logon id here, uid part is moved to getuid */
235 DWORD length = sizeof (name);
236 if (GetUserName (name, &length))
237 strcpy (the_passwd.pw_name, name);
239 strcpy (the_passwd.pw_name, "unknown");
242 /* Ensure HOME and SHELL are defined. */
245 * With XEmacs, setting $HOME is deprecated.
247 if (getenv ("HOME") == NULL)
250 if (getenv ("SHELL") == NULL)
251 putenv ((GetVersion () & 0x80000000) ? "SHELL=command" : "SHELL=cmd");
253 /* Set dir and shell from environment variables. */
254 strcpy (the_passwd.pw_dir, (char *)get_home_directory());
255 strcpy (the_passwd.pw_shell, getenv ("SHELL"));
258 /* Normalize filename by converting all path separators to
259 the specified separator. Also conditionally convert upper
260 case path name components to lower case. */
263 normalize_filename (char *fp, char path_sep)
268 /* Always lower-case drive letters a-z, even if the filesystem
269 preserves case in filenames.
270 This is so filenames can be compared by string comparison
271 functions that are case-sensitive. Even case-preserving filesystems
272 do not distinguish case in drive letters. */
273 if (fp[1] == ':' && *fp >= 'A' && *fp <= 'Z')
279 if (NILP (Vmswindows_downcase_file_names))
283 if (*fp == '/' || *fp == '\\')
290 sep = path_sep; /* convert to this path separator */
291 elem = fp; /* start of current path element */
294 if (*fp >= 'a' && *fp <= 'z')
295 elem = 0; /* don't convert this element */
297 if (*fp == 0 || *fp == ':')
299 sep = *fp; /* restore current separator (or 0) */
300 *fp = '/'; /* after conversion of this element */
303 if (*fp == '/' || *fp == '\\')
305 if (elem && elem != fp)
307 *fp = 0; /* temporary end of string */
308 _strlwr (elem); /* while we convert to lower case */
310 *fp = sep; /* convert (or restore) path separator */
311 elem = fp + 1; /* next element starts after separator */
317 /* Destructively turn backslashes into slashes. */
319 dostounix_filename (char *p)
321 normalize_filename (p, '/');
324 /* Destructively turn slashes into backslashes. */
326 unixtodos_filename (char *p)
328 normalize_filename (p, '\\');
331 /* Remove all CR's that are followed by a LF.
332 (From msdos.c...probably should figure out a way to share it,
333 although this code isn't going to ever change.) */
335 crlf_to_lf (int n, unsigned char *buf, unsigned *lf_count)
337 unsigned char *np = buf;
338 unsigned char *startp = buf;
339 unsigned char *endp = buf + n;
343 while (buf < endp - 1)
349 if (*(++buf) != 0x0a)
364 /* Parse the root part of file name, if present. Return length and
365 optionally store pointer to char after root. */
367 parse_root (char * name, char ** pPath)
374 /* find the root name of the volume if given */
375 if (isalpha (name[0]) && name[1] == ':')
377 /* skip past drive specifier */
379 if (IS_DIRECTORY_SEP (name[0]))
382 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
388 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
393 if (IS_DIRECTORY_SEP (name[0]))
403 /* Get long base name for name; name is assumed to be absolute. */
405 get_long_basename (char * name, char * buf, int size)
407 WIN32_FIND_DATA find_data;
413 /* If the last component of NAME has a wildcard character,
414 return it as the basename. */
415 p = name + strlen (name);
416 while (*p != '\\' && *p != ':' && p > name) p--;
418 if (strchr (p, '*') || strchr (p, '?'))
420 if ((len = strlen (p)) < size)
421 memcpy (buf, p, len + 1);
428 dir_handle = FindFirstFile (name, &find_data);
429 if (dir_handle != INVALID_HANDLE_VALUE)
431 if ((len = strlen (find_data.cFileName)) < size)
432 memcpy (buf, find_data.cFileName, len + 1);
435 FindClose (dir_handle);
440 /* Get long name for file, if possible (assumed to be absolute). */
442 win32_get_long_filename (char * name, char * buf, int size)
447 char full[ MAX_PATH ];
454 /* Use local copy for destructive modification. */
455 memcpy (full, name, len+1);
456 unixtodos_filename (full);
458 /* Copy root part verbatim. */
459 len = parse_root (full, &p);
460 memcpy (o, full, len);
467 p = strchr (q, '\\');
469 len = get_long_basename (full, o, size);
487 while (p != NULL && *p);
493 /* Routines that are no-ops on NT but are defined to get Emacs to compile. */
495 #if 0 /* #### We do not need those, do we? -kkm */
497 unrequest_sigio (void)
509 #define REG_ROOT "SOFTWARE\\GNU\\XEmacs"
512 nt_get_resource (char *key, LPDWORD lpdwtype)
515 HKEY hrootkey = NULL;
518 /* Check both the current user and the local machine to see if
519 we have any resources. */
521 if (RegOpenKeyEx (HKEY_CURRENT_USER, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
525 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
526 && (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL
527 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
532 if (lpvalue) xfree (lpvalue);
534 RegCloseKey (hrootkey);
537 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
541 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS &&
542 (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL &&
543 RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
548 if (lpvalue) xfree (lpvalue);
550 RegCloseKey (hrootkey);
557 init_environment (void)
559 /* Check for environment variables and use registry if they don't exist */
565 static char * env_vars[] =
579 #if defined (HEAP_IN_DATA) && !defined(PDUMP)
580 cache_system_info ();
582 for (i = 0; i < countof (env_vars); i++)
584 if (!getenv (env_vars[i]) &&
585 (lpval = nt_get_resource (env_vars[i], &dwType)) != NULL)
587 if (dwType == REG_EXPAND_SZ)
589 char buf1[500], buf2[500];
591 ExpandEnvironmentStrings ((LPSTR) lpval, buf1, 500);
592 _snprintf (buf2, 499, "%s=%s", env_vars[i], buf1);
593 putenv (strdup (buf2));
595 else if (dwType == REG_SZ)
599 _snprintf (buf, 499, "%s=%s", env_vars[i], lpval);
600 putenv (strdup (buf));
608 /* Another special case: on NT, the PATH variable is actually named
609 "Path" although cmd.exe (perhaps NT itself) arranges for
610 environment variable lookup and setting to be case insensitive.
611 However, Emacs assumes a fully case sensitive environment, so we
612 need to change "Path" to "PATH" to match the expectations of
613 various elisp packages. We do this by the sneaky method of
614 modifying the string in the C runtime environ entry.
616 The same applies to COMSPEC. */
620 for (envp = environ; *envp; envp++)
621 if (_strnicmp (*envp, "PATH=", 5) == 0)
622 memcpy (*envp, "PATH=", 5);
623 else if (_strnicmp (*envp, "COMSPEC=", 8) == 0)
624 memcpy (*envp, "COMSPEC=", 8);
627 /* Remember the initial working directory for getwd, then make the
628 real wd be the location of emacs.exe to avoid conflicts when
629 renaming or deleting directories. (We also don't call chdir when
630 running subprocesses for the same reason.) */
631 if (!GetCurrentDirectory (MAXPATHLEN, startup_dir))
636 char modname[MAX_PATH];
638 if (!GetModuleFileName (NULL, modname, MAX_PATH))
640 if ((p = strrchr (modname, '\\')) == NULL)
644 SetCurrentDirectory (modname);
650 #ifndef HAVE_X_WINDOWS
651 /* X11R6 on NT provides the single parameter version of this command. */
653 #include <sys/timeb.h>
655 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
657 gettimeofday (struct timeval *tv, struct timezone *tz)
662 tv->tv_sec = tb.time;
663 tv->tv_usec = tb.millitm * 1000L;
666 tz->tz_minuteswest = tb.timezone; /* minutes west of Greenwich */
667 tz->tz_dsttime = tb.dstflag; /* type of dst correction */
671 #endif /* HAVE_X_WINDOWS */
673 /* ------------------------------------------------------------------------- */
674 /* IO support and wrapper functions for Win32 API. */
675 /* ------------------------------------------------------------------------- */
677 /* Place a wrapper around the MSVC version of ctime. It returns NULL
678 on network directories, so we handle that case here.
679 (Ulrich Leodolter, 1/11/95). */
681 sys_ctime (const time_t *t)
683 char *str = (char *) ctime (t);
684 return (str ? str : "Sun Jan 01 00:00:00 1970");
687 /* Emulate sleep...we could have done this with a define, but that
688 would necessitate including windows.h in the files that used it.
689 This is much easier. */
691 #ifndef HAVE_X_WINDOWS
693 sys_sleep (int seconds)
695 Sleep (seconds * 1000);
699 /* #### This is an evil dirty hack. We must get rid of it.
700 Word "munging" is not in XEmacs lexicon. - kkm */
702 /* Internal MSVC data and functions for low-level descriptor munging */
703 #if (_MSC_VER == 900)
704 extern char _osfile[];
706 extern int __cdecl _set_osfhnd (int fd, long h);
707 extern int __cdecl _free_osfhnd (int fd);
709 /* parallel array of private info on file handles */
710 filedesc fd_info [ MAXDESC ];
712 typedef struct volume_info_data {
713 struct volume_info_data * next;
715 /* time when info was obtained */
718 /* actual volume info */
727 /* Global referenced by various functions. */
728 static volume_info_data volume_info;
730 /* Vector to indicate which drives are local and fixed (for which cached
731 data never expires). */
732 static BOOL fixed_drives[26];
734 /* Consider cached volume information to be stale if older than 10s,
735 at least for non-local drives. Info for fixed drives is never stale. */
736 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
737 #define VOLINFO_STILL_VALID( root_dir, info ) \
738 ( ( isalpha (root_dir[0]) && \
739 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
740 || GetTickCount () - info->timestamp < 10000 )
742 /* Cache support functions. */
744 /* Simple linked list with linear search is sufficient. */
745 static volume_info_data *volume_cache = NULL;
747 static volume_info_data *
748 lookup_volume_info (char * root_dir)
750 volume_info_data * info;
752 for (info = volume_cache; info; info = info->next)
753 if (stricmp (info->root_dir, root_dir) == 0)
759 add_volume_info (char * root_dir, volume_info_data * info)
761 info->root_dir = xstrdup (root_dir);
762 info->next = volume_cache;
767 /* Wrapper for GetVolumeInformation, which uses caching to avoid
768 performance penalty (~2ms on 486 for local drives, 7.5ms for local
769 cdrom drive, ~5-10ms or more for remote drives on LAN). */
771 GetCachedVolumeInformation (char * root_dir)
773 volume_info_data * info;
774 char default_root[ MAX_PATH ];
776 /* NULL for root_dir means use root from current directory. */
777 if (root_dir == NULL)
779 if (GetCurrentDirectory (MAX_PATH, default_root) == 0)
781 parse_root (default_root, &root_dir);
783 root_dir = default_root;
786 /* Local fixed drives can be cached permanently. Removable drives
787 cannot be cached permanently, since the volume name and serial
788 number (if nothing else) can change. Remote drives should be
789 treated as if they are removable, since there is no sure way to
790 tell whether they are or not. Also, the UNC association of drive
791 letters mapped to remote volumes can be changed at any time (even
792 by other processes) without notice.
794 As a compromise, so we can benefit from caching info for remote
795 volumes, we use a simple expiry mechanism to invalidate cache
796 entries that are more than ten seconds old. */
799 /* No point doing this, because WNetGetConnection is even slower than
800 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
801 GetDriveType is about the only call of this type which does not
802 involve network access, and so is extremely quick). */
804 /* Map drive letter to UNC if remote. */
805 if ( isalpha( root_dir[0] ) && !fixed[ DRIVE_INDEX( root_dir[0] ) ] )
807 char remote_name[ 256 ];
808 char drive[3] = { root_dir[0], ':' };
810 if (WNetGetConnection (drive, remote_name, sizeof (remote_name))
816 info = lookup_volume_info (root_dir);
818 if (info == NULL || ! VOLINFO_STILL_VALID (root_dir, info))
826 /* Info is not cached, or is stale. */
827 if (!GetVolumeInformation (root_dir,
832 type, sizeof (type)))
835 /* Cache the volume information for future use, overwriting existing
839 info = (volume_info_data *) xmalloc (sizeof (volume_info_data));
840 add_volume_info (root_dir, info);
848 info->name = xstrdup (name);
849 info->serialnum = serialnum;
850 info->maxcomp = maxcomp;
852 info->type = xstrdup (type);
853 info->timestamp = GetTickCount ();
859 /* Get information on the volume where name is held; set path pointer to
860 start of pathname in name (past UNC header\volume header if present). */
862 get_volume_info (const char * name, const char ** pPath)
865 char *rootname = NULL; /* default to current volume */
866 volume_info_data * info;
871 /* find the root name of the volume if given */
872 if (isalpha (name[0]) && name[1] == ':')
880 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
887 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
900 info = GetCachedVolumeInformation (rootname);
903 /* Set global referenced by other functions. */
910 /* Determine if volume is FAT format (ie. only supports short 8.3
911 names); also set path pointer to start of pathname in name. */
913 is_fat_volume (const char * name, const char ** pPath)
915 if (get_volume_info (name, pPath))
916 return (volume_info.maxcomp == 12);
920 /* Map filename to a legal 8.3 name if necessary. */
922 map_win32_filename (const char * name, const char ** pPath)
924 static char shortname[MAX_PATH];
925 char * str = shortname;
928 const char * save_name = name;
930 if (is_fat_volume (name, &path)) /* truncate to 8.3 */
932 REGISTER int left = 8; /* maximum number of chars in part */
933 REGISTER int extn = 0; /* extension added? */
934 REGISTER int dots = 2; /* maximum number of dots allowed */
937 *str++ = *name++; /* skip past UNC header */
939 while ((c = *name++))
946 extn = 0; /* reset extension flags */
947 dots = 2; /* max 2 dots */
948 left = 8; /* max length 8 for main part */
952 extn = 0; /* reset extension flags */
953 dots = 2; /* max 2 dots */
954 left = 8; /* max length 8 for main part */
959 /* Convert path components of the form .xxx to _xxx,
960 but leave . and .. as they are. This allows .emacs
961 to be read as _emacs, for example. */
965 IS_DIRECTORY_SEP (*name))
980 extn = 1; /* we've got an extension */
981 left = 3; /* 3 chars in extension */
985 /* any embedded dots after the first are converted to _ */
990 case '#': /* don't lose these, they're important */
992 str[-1] = c; /* replace last character of part */
997 *str++ = tolower (c); /* map to lower case (looks nicer) */
999 dots = 0; /* started a path component */
1008 strcpy (shortname, name);
1009 unixtodos_filename (shortname);
1013 *pPath = shortname + (path - save_name);
1019 /* Emulate the Unix directory procedures opendir, closedir,
1020 and readdir. We can't use the procedures supplied in sysdep.c,
1021 so we provide them here. */
1023 struct direct dir_static; /* simulated directory contents */
1024 static HANDLE dir_find_handle = INVALID_HANDLE_VALUE;
1025 static int dir_is_fat;
1026 static char dir_pathname[MAXPATHLEN+1];
1027 static WIN32_FIND_DATA dir_find_data;
1030 opendir (const char *filename)
1034 /* Opening is done by FindFirstFile. However, a read is inherent to
1035 this operation, so we defer the open until read time. */
1037 if (!(dirp = xnew_and_zero(DIR)))
1039 if (dir_find_handle != INVALID_HANDLE_VALUE)
1046 strncpy (dir_pathname, map_win32_filename (filename, NULL), MAXPATHLEN);
1047 dir_pathname[MAXPATHLEN] = '\0';
1048 dir_is_fat = is_fat_volume (filename, NULL);
1054 closedir (DIR *dirp)
1058 /* If we have a find-handle open, close it. */
1059 if (dir_find_handle != INVALID_HANDLE_VALUE)
1061 retval = FindClose (dir_find_handle);
1062 dir_find_handle = INVALID_HANDLE_VALUE;
1074 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
1075 if (dir_find_handle == INVALID_HANDLE_VALUE)
1077 char filename[MAXNAMLEN + 3];
1080 strcpy (filename, dir_pathname);
1081 ln = strlen (filename) - 1;
1082 if (!IS_DIRECTORY_SEP (filename[ln]))
1083 strcat (filename, "\\");
1084 strcat (filename, "*");
1086 dir_find_handle = FindFirstFile (filename, &dir_find_data);
1088 if (dir_find_handle == INVALID_HANDLE_VALUE)
1093 if (!FindNextFile (dir_find_handle, &dir_find_data))
1097 /* Emacs never uses this value, so don't bother making it match
1098 value returned by xemacs_stat(). */
1099 dir_static.d_ino = 1;
1101 dir_static.d_reclen = sizeof (struct direct) - MAXNAMLEN + 3 +
1102 dir_static.d_namlen - dir_static.d_namlen % 4;
1104 dir_static.d_namlen = strlen (dir_find_data.cFileName);
1105 strcpy (dir_static.d_name, dir_find_data.cFileName);
1107 _strlwr (dir_static.d_name);
1108 else if (!NILP (Vmswindows_downcase_file_names))
1111 for (p = dir_static.d_name; *p; p++)
1112 if (*p >= 'a' && *p <= 'z')
1115 _strlwr (dir_static.d_name);
1122 /* #### Have to check if all that sad story about '95 is true - kkm */
1124 sys_rename (const char * oldname, const char * newname)
1126 char temp[MAX_PATH];
1129 /* MoveFile on Win95 doesn't correctly change the short file name
1130 alias in a number of circumstances (it is not easy to predict when
1131 just by looking at oldname and newname, unfortunately). In these
1132 cases, renaming through a temporary name avoids the problem.
1134 A second problem on Win95 is that renaming through a temp name when
1135 newname is uppercase fails (the final long name ends up in
1136 lowercase, although the short alias might be uppercase) UNLESS the
1137 long temp name is not 8.3.
1139 So, on Win95 we always rename through a temp name, and we make sure
1140 the temp name has a long extension to ensure correct renaming. */
1142 strcpy (temp, map_win32_filename (oldname, NULL));
1144 if (GetVersion () & 0x80000000)
1148 if (p = strrchr (temp, '\\'))
1152 /* Force temp name to require a manufactured 8.3 alias - this
1153 seems to make the second rename work properly. */
1154 strcpy (p, "_rename_temp.XXXXXX");
1156 if (rename (map_win32_filename (oldname, NULL), temp) < 0)
1160 /* Emulate Unix behavior - newname is deleted if it already exists
1161 (at least if it is a file; don't do this for directories).
1162 However, don't do this if we are just changing the case of the file
1163 name - we will end up deleting the file we are trying to rename! */
1164 newname = map_win32_filename (newname, NULL);
1166 /* TODO: Use GetInformationByHandle (on NT) to ensure newname and temp
1167 do not refer to the same file, eg. through share aliases. */
1168 if (stricmp (newname, temp) != 0
1169 && (attr = GetFileAttributes (newname)) != -1
1170 && (attr & FILE_ATTRIBUTE_DIRECTORY) == 0)
1172 _chmod (newname, 0666);
1176 return rename (temp, newname);
1180 static FILETIME utc_base_ft;
1181 static long double utc_base;
1182 static int init = 0;
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 static LARGE_INTEGER utc_base_li;
1222 convert_time (FILETIME uft)
1229 TIME_ZONE_INFORMATION tzi;
1237 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
1246 st.wMilliseconds = 0;
1248 SystemTimeToFileTime (&st, &utc_base_ft);
1250 utc_base_li.LowPart = utc_base_ft.dwLowDateTime;
1251 utc_base_li.HighPart = utc_base_ft.dwHighDateTime;
1258 /* On a compiler that supports long integers, do it the easy way */
1259 lft.LowPart = uft.dwLowDateTime;
1260 lft.HighPart = uft.dwHighDateTime;
1261 ret = (time_t) ((lft.QuadPart - utc_base_li.QuadPart) / 10000000);
1265 /* Do it the hard way using mktime. */
1266 FileTimeToLocalFileTime(&uft, &ft);
1267 FileTimeToSystemTime (&ft, &st);
1268 tzid = GetTimeZoneInformation (&tzi);
1269 t.tm_year = st.wYear - 1900;
1270 t.tm_mon = st.wMonth - 1;
1271 t.tm_mday = st.wDay;
1272 t.tm_hour = st.wHour;
1273 t.tm_min = st.wMinute;
1274 t.tm_sec = st.wSecond;
1275 t.tm_isdst = (tzid == TIME_ZONE_ID_DAYLIGHT);
1276 /* st.wMilliseconds not applicable */
1288 #if defined(MINGW) && CYGWIN_VERSION_DLL_MAJOR <= 21
1294 /* in case we ever have need of this */
1296 convert_from_time_t (time_t time, FILETIME * pft)
1302 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
1311 st.wMilliseconds = 0;
1313 SystemTimeToFileTime (&st, &utc_base_ft);
1314 utc_base = (long double) utc_base_ft.dwHighDateTime
1315 * 4096 * 1024 * 1024 + utc_base_ft.dwLowDateTime;
1319 /* time in 100ns units since 1-Jan-1601 */
1320 tmp = (long double) time * 1e7 + utc_base;
1321 pft->dwHighDateTime = (DWORD) (tmp / (4096.0 * 1024 * 1024));
1322 pft->dwLowDateTime = (DWORD) (tmp - pft->dwHighDateTime);
1327 /* No reason to keep this; faking inode values either by hashing or even
1328 using the file index from GetInformationByHandle, is not perfect and
1329 so by default Emacs doesn't use the inode values on Windows.
1330 Instead, we now determine file-truename correctly (except for
1331 possible drive aliasing etc). */
1333 /* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
1335 hashval (const unsigned char * str)
1340 h = (h << 4) + *str++;
1346 /* Return the hash value of the canonical pathname, excluding the
1347 drive/UNC header, to get a hopefully unique inode number. */
1349 generate_inode_val (const char * name)
1351 char fullname[ MAX_PATH ];
1355 /* Get the truly canonical filename, if it exists. (Note: this
1356 doesn't resolve aliasing due to subst commands, or recognize hard
1358 if (!win32_get_long_filename ((char *)name, fullname, MAX_PATH))
1361 parse_root (fullname, &p);
1362 /* Normal Win32 filesystems are still case insensitive. */
1369 /* #### aichner@ecf.teradyne.com reported that with the library
1370 provided stat/fstat, (file-exist "d:\\tmp\\") =>> nil,
1371 (file-exist "d:\\tmp") =>> t, when d:\tmp exists. Whenever
1372 we opt to use non-encapsulated stat(), this should serve as
1373 a compatibility test. --kkm */
1375 /* Since stat is encapsulated on Windows NT, we need to encapsulate
1376 the equally broken fstat as well. FSFmacs also provides its own
1377 utime. Is that necessary here too? */
1379 mswindows_fstat (int desc, struct stat * buf)
1381 HANDLE fh = (HANDLE) _get_osfhandle (desc);
1382 BY_HANDLE_FILE_INFORMATION info;
1386 switch (GetFileType (fh) & ~FILE_TYPE_REMOTE)
1388 case FILE_TYPE_DISK:
1389 buf->st_mode = _S_IFREG;
1390 if (!GetFileInformationByHandle (fh, &info))
1396 case FILE_TYPE_PIPE:
1397 buf->st_mode = _S_IFIFO;
1399 case FILE_TYPE_CHAR:
1400 case FILE_TYPE_UNKNOWN:
1402 buf->st_mode = _S_IFCHR;
1404 memset (&info, 0, sizeof (info));
1405 info.dwFileAttributes = 0;
1406 info.ftCreationTime = utc_base_ft;
1407 info.ftLastAccessTime = utc_base_ft;
1408 info.ftLastWriteTime = utc_base_ft;
1411 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1413 buf->st_mode = _S_IFDIR;
1414 buf->st_nlink = 2; /* doesn't really matter */
1415 fake_inode = 0; /* this doesn't either I think */
1419 buf->st_nlink = (short) info.nNumberOfLinks;
1420 /* Might as well use file index to fake inode values, but this
1421 is not guaranteed to be unique unless we keep a handle open
1422 all the time (even then there are situations where it is
1423 not unique). Reputedly, there are at most 48 bits of info
1424 (on NTFS, presumably less on FAT). */
1425 fake_inode = info.nFileIndexLow ^ info.nFileIndexHigh;
1428 /* MSVC defines _ino_t to be short; other libc's might not. */
1429 if (sizeof (buf->st_ino) == 2)
1430 buf->st_ino = (unsigned short) (fake_inode ^ (fake_inode >> 16));
1432 buf->st_ino = (unsigned short) fake_inode;
1434 /* consider files to belong to current user */
1438 buf->st_dev = info.dwVolumeSerialNumber;
1439 buf->st_rdev = info.dwVolumeSerialNumber;
1441 buf->st_size = info.nFileSizeLow;
1443 /* Convert timestamps to Unix format. */
1444 buf->st_mtime = convert_time (info.ftLastWriteTime);
1445 buf->st_atime = convert_time (info.ftLastAccessTime);
1446 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
1447 buf->st_ctime = convert_time (info.ftCreationTime);
1448 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
1450 /* determine rwx permissions */
1451 if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
1452 permission = _S_IREAD;
1454 permission = _S_IREAD | _S_IWRITE;
1456 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1457 permission |= _S_IEXEC;
1459 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
1464 /* MSVC stat function can't cope with UNC names and has other bugs, so
1465 replace it with our own. This also allows us to calculate consistent
1466 inode values without hacks in the main Emacs code. */
1468 mswindows_stat (const char * path, struct stat * buf)
1471 WIN32_FIND_DATA wfd;
1476 int rootdir = FALSE;
1478 if (path == NULL || buf == NULL)
1484 name = (char *) map_win32_filename (path, &path);
1485 /* must be valid filename, no wild cards */
1486 if (strchr (name, '*') || strchr (name, '?'))
1492 /* Remove trailing directory separator, unless name is the root
1493 directory of a drive or UNC volume in which case ensure there
1494 is a trailing separator. */
1495 len = strlen (name);
1496 rootdir = (path >= name + len - 1
1497 && (IS_DIRECTORY_SEP (*path) || *path == 0));
1498 name = strcpy ((char *)alloca (len + 2), name);
1502 if (!IS_DIRECTORY_SEP (name[len-1]))
1503 strcat (name, "\\");
1504 if (GetDriveType (name) < 2)
1509 memset (&wfd, 0, sizeof (wfd));
1510 wfd.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
1511 wfd.ftCreationTime = utc_base_ft;
1512 wfd.ftLastAccessTime = utc_base_ft;
1513 wfd.ftLastWriteTime = utc_base_ft;
1514 strcpy (wfd.cFileName, name);
1518 if (IS_DIRECTORY_SEP (name[len-1]))
1521 /* (This is hacky, but helps when doing file completions on
1522 network drives.) Optimize by using information available from
1523 active readdir if possible. */
1524 if (dir_find_handle != INVALID_HANDLE_VALUE &&
1525 (len = strlen (dir_pathname)),
1526 strnicmp (name, dir_pathname, len) == 0 &&
1527 IS_DIRECTORY_SEP (name[len]) &&
1528 stricmp (name + len + 1, dir_static.d_name) == 0)
1530 /* This was the last entry returned by readdir. */
1531 wfd = dir_find_data;
1535 fh = FindFirstFile (name, &wfd);
1536 if (fh == INVALID_HANDLE_VALUE)
1545 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1547 buf->st_mode = _S_IFDIR;
1548 buf->st_nlink = 2; /* doesn't really matter */
1549 fake_inode = 0; /* this doesn't either I think */
1551 else if (!NILP (Vmswindows_get_true_file_attributes))
1553 /* This is more accurate in terms of getting the correct number
1554 of links, but is quite slow (it is noticeable when Emacs is
1555 making a list of file name completions). */
1556 BY_HANDLE_FILE_INFORMATION info;
1558 /* No access rights required to get info. */
1559 fh = CreateFile (name, 0, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
1560 OPEN_EXISTING, 0, NULL);
1562 if (GetFileInformationByHandle (fh, &info))
1564 switch (GetFileType (fh))
1566 case FILE_TYPE_DISK:
1567 buf->st_mode = _S_IFREG;
1569 case FILE_TYPE_PIPE:
1570 buf->st_mode = _S_IFIFO;
1572 case FILE_TYPE_CHAR:
1573 case FILE_TYPE_UNKNOWN:
1575 buf->st_mode = _S_IFCHR;
1577 buf->st_nlink = (short) info.nNumberOfLinks;
1578 /* Might as well use file index to fake inode values, but this
1579 is not guaranteed to be unique unless we keep a handle open
1580 all the time (even then there are situations where it is
1581 not unique). Reputedly, there are at most 48 bits of info
1582 (on NTFS, presumably less on FAT). */
1583 fake_inode = info.nFileIndexLow ^ info.nFileIndexHigh;
1594 /* Don't bother to make this information more accurate. */
1595 buf->st_mode = _S_IFREG;
1601 /* Not sure if there is any point in this. */
1602 if (!NILP (Vwin32_generate_fake_inodes))
1603 fake_inode = generate_inode_val (name);
1604 else if (fake_inode == 0)
1606 /* For want of something better, try to make everything unique. */
1607 static DWORD gen_num = 0;
1608 fake_inode = ++gen_num;
1612 /* #### MSVC defines _ino_t to be short; other libc's might not. */
1613 buf->st_ino = (unsigned short) (fake_inode ^ (fake_inode >> 16));
1615 /* consider files to belong to current user */
1616 buf->st_uid = buf->st_gid = (short) nt_fake_unix_uid;
1618 /* volume_info is set indirectly by map_win32_filename */
1619 buf->st_dev = volume_info.serialnum;
1620 buf->st_rdev = volume_info.serialnum;
1622 buf->st_size = wfd.nFileSizeLow;
1624 /* Convert timestamps to Unix format. */
1625 buf->st_mtime = convert_time (wfd.ftLastWriteTime);
1626 buf->st_atime = convert_time (wfd.ftLastAccessTime);
1627 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
1628 buf->st_ctime = convert_time (wfd.ftCreationTime);
1629 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
1631 /* determine rwx permissions */
1632 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
1633 permission = _S_IREAD;
1635 permission = _S_IREAD | _S_IWRITE;
1637 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1638 permission |= _S_IEXEC;
1641 char * p = strrchr (name, '.');
1643 (stricmp (p, ".exe") == 0 ||
1644 stricmp (p, ".com") == 0 ||
1645 stricmp (p, ".bat") == 0 ||
1646 stricmp (p, ".cmd") == 0))
1647 permission |= _S_IEXEC;
1650 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
1655 /* From callproc.c */
1656 extern Lisp_Object Vbinary_process_input;
1657 extern Lisp_Object Vbinary_process_output;
1659 /* Unix pipe() has only one arg */
1661 sys_pipe (int * phandles)
1666 /* make pipe handles non-inheritable; when we spawn a child, we
1667 replace the relevant handle with an inheritable one. Also put
1668 pipes into binary mode; we will do text mode translation ourselves
1670 rc = _pipe (phandles, 0, _O_NOINHERIT | _O_BINARY);
1674 flags = FILE_PIPE | FILE_READ;
1675 if (!NILP (Vbinary_process_output))
1676 flags |= FILE_BINARY;
1677 fd_info[phandles[0]].flags = flags;
1679 flags = FILE_PIPE | FILE_WRITE;
1680 if (!NILP (Vbinary_process_input))
1681 flags |= FILE_BINARY;
1682 fd_info[phandles[1]].flags = flags;
1689 term_ntproc (int unused)
1696 /* Initial preparation for subprocess support: replace our standard
1697 handles with non-inheritable versions. */
1700 HANDLE stdin_save = INVALID_HANDLE_VALUE;
1701 HANDLE stdout_save = INVALID_HANDLE_VALUE;
1702 HANDLE stderr_save = INVALID_HANDLE_VALUE;
1704 parent = GetCurrentProcess ();
1706 /* ignore errors when duplicating and closing; typically the
1707 handles will be invalid when running as a gui program. */
1708 DuplicateHandle (parent,
1709 GetStdHandle (STD_INPUT_HANDLE),
1714 DUPLICATE_SAME_ACCESS);
1716 DuplicateHandle (parent,
1717 GetStdHandle (STD_OUTPUT_HANDLE),
1722 DUPLICATE_SAME_ACCESS);
1724 DuplicateHandle (parent,
1725 GetStdHandle (STD_ERROR_HANDLE),
1730 DUPLICATE_SAME_ACCESS);
1736 if (stdin_save != INVALID_HANDLE_VALUE)
1737 _open_osfhandle ((long) stdin_save, O_TEXT);
1739 _open ("nul", O_TEXT | O_NOINHERIT | O_RDONLY);
1742 if (stdout_save != INVALID_HANDLE_VALUE)
1743 _open_osfhandle ((long) stdout_save, O_TEXT);
1745 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
1748 if (stderr_save != INVALID_HANDLE_VALUE)
1749 _open_osfhandle ((long) stderr_save, O_TEXT);
1751 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
1755 /* unfortunately, atexit depends on implementation of malloc */
1756 /* atexit (term_ntproc); */
1757 signal (SIGABRT, term_ntproc);
1759 /* determine which drives are fixed, for GetCachedVolumeInformation */
1761 /* GetDriveType must have trailing backslash. */
1762 char drive[] = "A:\\";
1764 /* Loop over all possible drive letters */
1765 while ( *drive <= 'Z' )
1767 /* Record if this drive letter refers to a fixed drive. */
1768 fixed_drives[ DRIVE_INDEX (*drive) ] =
1769 (GetDriveType (drive) == DRIVE_FIXED);
1777 tty_semi_canonicalize_console_connection (Lisp_Object connection,
1778 Error_behavior errb)
1784 tty_canonicalize_console_connection (Lisp_Object connection,
1785 Error_behavior errb)
1791 tty_semi_canonicalize_device_connection (Lisp_Object connection,
1792 Error_behavior errb)
1798 tty_canonicalize_device_connection (Lisp_Object connection,
1799 Error_behavior errb)
1805 /*--------------------------------------------------------------------*/
1806 /* Signal support */
1807 /*--------------------------------------------------------------------*/
1809 /* We need MS-defined signal and raise here */
1813 #define sigmask(nsig) (1U << nsig)
1815 /* We can support as many signals as fit into word */
1818 /* Signal handlers. Initial value = 0 = SIG_DFL */
1819 static void (__cdecl *signal_handlers[SIG_MAX])(int) = {0};
1821 /* Signal block mask: bit set to 1 means blocked */
1822 unsigned signal_block_mask = 0;
1824 /* Signal pending mask: bit set to 1 means sig is pending */
1825 unsigned signal_pending_mask = 0;
1827 mswindows_sighandler mswindows_sigset (int nsig, mswindows_sighandler handler)
1829 /* We delegate some signals to the system function */
1830 if (nsig == SIGFPE || nsig == SIGABRT || nsig == SIGINT)
1831 return signal (nsig, handler);
1833 if (nsig < 0 || nsig > SIG_MAX)
1839 /* Store handler ptr */
1841 mswindows_sighandler old_handler = signal_handlers[nsig];
1842 signal_handlers[nsig] = handler;
1847 int mswindows_sighold (int nsig)
1849 if (nsig < 0 || nsig > SIG_MAX)
1850 return errno = EINVAL;
1852 signal_block_mask |= sigmask(nsig);
1856 int mswindows_sigrelse (int nsig)
1858 if (nsig < 0 || nsig > SIG_MAX)
1859 return errno = EINVAL;
1861 signal_block_mask &= ~sigmask(nsig);
1863 if (signal_pending_mask & sigmask(nsig))
1864 mswindows_raise (nsig);
1869 int mswindows_sigpause (int nsig)
1871 /* This is currently not called, because the only
1872 call to sigpause inside XEmacs is with SIGCHLD
1873 parameter. Just in case, we put an assert here,
1874 so anyone who will add a call to sigpause will
1875 be surprised (or surprise someone else...) */
1880 int mswindows_raise (int nsig)
1882 /* We delegate some raises to the system routine */
1883 if (nsig == SIGFPE || nsig == SIGABRT || nsig == SIGINT)
1884 return raise (nsig);
1886 if (nsig < 0 || nsig > SIG_MAX)
1887 return errno = EINVAL;
1889 /* If the signal is blocked, remember to issue later */
1890 if (signal_block_mask & sigmask(nsig))
1892 signal_pending_mask |= sigmask(nsig);
1896 if (signal_handlers[nsig] == SIG_IGN)
1899 if (signal_handlers[nsig] != SIG_DFL)
1901 (*signal_handlers[nsig])(nsig);
1905 /* Default signal actions */
1906 if (nsig == SIGALRM || nsig == SIGPROF)
1909 /* Other signals are ignored by default */
1913 /*--------------------------------------------------------------------*/
1915 /*--------------------------------------------------------------------*/
1917 /* We emulate two timers, one for SIGALRM, another for SIGPROF.
1919 itimerproc() function has an implementation limitation: it does
1920 not allow to set *both* interval and period. If an attempt is
1921 made to set both, and then they are unequal, the function
1924 Minimum timer resolution on Win32 systems varies, and is greater
1925 than or equal than 1 ms. The resolution is always wrapped not to
1926 attempt to get below the system defined limit.
1929 /* Timer precision, denominator of one fraction: for 100 ms
1930 interval, request 10 ms precision
1932 const int timer_prec = 10;
1934 /* Last itimervals, as set by calls to setitimer */
1935 static struct itimerval it_alarm;
1936 static struct itimerval it_prof;
1938 /* Timer IDs as returned by MM */
1939 MMRESULT tid_alarm = 0;
1940 MMRESULT tid_prof = 0;
1942 static void CALLBACK timer_proc (UINT uID, UINT uMsg, DWORD dwUser,
1943 DWORD dw1, DWORD dw2)
1945 /* Just raise a signal indicated by dwUser parameter */
1946 mswindows_raise (dwUser);
1949 /* Divide time in ms specified by IT by DENOM. Return 1 ms
1950 if division results in zero */
1951 static UINT period (const struct itimerval* it, UINT denom)
1953 static TIMECAPS time_caps;
1956 const struct timeval* tv =
1957 (it->it_value.tv_sec == 0 && it->it_value.tv_usec == 0)
1958 ? &it->it_interval : &it->it_value;
1960 /* Zero means stop timer */
1961 if (tv->tv_sec == 0 && tv->tv_usec == 0)
1964 /* Convert to ms and divide by denom */
1965 res = (tv->tv_sec * 1000 + (tv->tv_usec + 500) / 1000) / denom;
1967 /* Converge to minimum timer resolution */
1968 if (time_caps.wPeriodMin == 0)
1969 timeGetDevCaps (&time_caps, sizeof(time_caps));
1971 if (res < time_caps.wPeriodMin)
1972 res = time_caps.wPeriodMin;
1977 static int setitimer_helper (const struct itimerval* itnew,
1978 struct itimerval* itold, struct itimerval* itcurrent,
1979 MMRESULT* tid, DWORD sigkind)
1981 UINT delay, resolution, event_type;
1983 /* First stop the old timer */
1986 timeKillEvent (*tid);
1987 timeEndPeriod (period (itcurrent, timer_prec));
1991 /* Return old itimerval if requested */
1993 *itold = *itcurrent;
1995 *itcurrent = *itnew;
1997 /* Determine if to start new timer */
1998 delay = period (itnew, 1);
2001 resolution = period (itnew, timer_prec);
2002 event_type = (itnew->it_value.tv_sec == 0 && itnew->it_value.tv_usec == 0)
2003 ? TIME_ONESHOT : TIME_PERIODIC;
2004 timeBeginPeriod (resolution);
2005 *tid = timeSetEvent (delay, resolution, timer_proc, sigkind, event_type);
2008 return !delay || *tid;
2011 int setitimer (int kind, const struct itimerval* itnew,
2012 struct itimerval* itold)
2014 /* In this version, both interval and value are allowed
2015 only if they are equal. */
2016 assert ((itnew->it_value.tv_sec == 0 && itnew->it_value.tv_usec == 0)
2017 || (itnew->it_interval.tv_sec == 0 && itnew->it_interval.tv_usec == 0)
2018 || (itnew->it_value.tv_sec == itnew->it_interval.tv_sec &&
2019 itnew->it_value.tv_usec == itnew->it_interval.tv_usec));
2021 if (kind == ITIMER_REAL)
2022 return setitimer_helper (itnew, itold, &it_alarm, &tid_alarm, SIGALRM);
2023 else if (kind == ITIMER_PROF)
2024 return setitimer_helper (itnew, itold, &it_prof, &tid_prof, SIGPROF);
2026 return errno = EINVAL;
2030 /*--------------------------------------------------------------------*/
2031 /* Memory-mapped files */
2032 /*--------------------------------------------------------------------*/
2035 open_input_file (file_data *p_file, const char *filename)
2037 /* Synched with FSF 20.6. We fixed some warnings. */
2039 HANDLE file_mapping;
2041 DWORD size, upper_size;
2043 file = CreateFile (filename, GENERIC_READ, FILE_SHARE_READ, NULL,
2044 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
2045 if (file == INVALID_HANDLE_VALUE)
2048 size = GetFileSize (file, &upper_size);
2049 file_mapping = CreateFileMapping (file, NULL, PAGE_READONLY,
2054 file_base = MapViewOfFile (file_mapping, FILE_MAP_READ, 0, 0, size);
2058 p_file->name = (char *)filename;
2059 p_file->size = size;
2060 p_file->file = file;
2061 p_file->file_mapping = file_mapping;
2062 p_file->file_base = (char *)file_base;
2068 open_output_file (file_data *p_file, const char *filename, unsigned long size)
2070 /* Synched with FSF 20.6. We fixed some warnings. */
2072 HANDLE file_mapping;
2075 file = CreateFile (filename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
2076 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
2077 if (file == INVALID_HANDLE_VALUE)
2080 file_mapping = CreateFileMapping (file, NULL, PAGE_READWRITE,
2085 file_base = MapViewOfFile (file_mapping, FILE_MAP_WRITE, 0, 0, size);
2086 if (file_base == NULL)
2089 p_file->name = filename;
2090 p_file->size = size;
2091 p_file->file = file;
2092 p_file->file_mapping = file_mapping;
2093 p_file->file_base = (char*) file_base;
2098 #if 1 /* !defined(MINGW) */
2099 /* Return pointer to section header for section containing the given
2100 relative virtual address. */
2101 static IMAGE_SECTION_HEADER *
2102 rva_to_section (DWORD rva, IMAGE_NT_HEADERS * nt_header)
2104 /* Synched with FSF 20.6. We added MINGW stuff. */
2105 PIMAGE_SECTION_HEADER section;
2108 section = IMAGE_FIRST_SECTION (nt_header);
2110 for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
2112 /* Some linkers (eg. the NT SDK linker I believe) swapped the
2113 meaning of these two values - or rather, they ignored
2114 VirtualSize entirely and always set it to zero. This affects
2115 some very old exes (eg. gzip dated Dec 1993). Since
2116 mswindows_executable_type relies on this function to work reliably,
2117 we need to cope with this. */
2118 DWORD real_size = max (section->SizeOfRawData,
2119 section->Misc.VirtualSize);
2120 if (rva >= section->VirtualAddress
2121 && rva < section->VirtualAddress + real_size)
2130 mswindows_executable_type (const char * filename, int * is_dos_app,
2131 int * is_cygnus_app)
2133 /* Synched with FSF 20.6. We added MINGW stuff and casts. */
2134 file_data executable;
2137 /* Default values in case we can't tell for sure. */
2138 *is_dos_app = FALSE;
2139 *is_cygnus_app = FALSE;
2141 if (!open_input_file (&executable, filename))
2144 p = strrchr (filename, '.');
2146 /* We can only identify DOS .com programs from the extension. */
2147 if (p && stricmp (p, ".com") == 0)
2149 else if (p && (stricmp (p, ".bat") == 0 ||
2150 stricmp (p, ".cmd") == 0))
2152 /* A DOS shell script - it appears that CreateProcess is happy to
2153 accept this (somewhat surprisingly); presumably it looks at
2154 COMSPEC to determine what executable to actually invoke.
2155 Therefore, we have to do the same here as well. */
2156 /* Actually, I think it uses the program association for that
2157 extension, which is defined in the registry. */
2158 p = egetenv ("COMSPEC");
2160 mswindows_executable_type (p, is_dos_app, is_cygnus_app);
2164 /* Look for DOS .exe signature - if found, we must also check that
2165 it isn't really a 16- or 32-bit Windows exe, since both formats
2166 start with a DOS program stub. Note that 16-bit Windows
2167 executables use the OS/2 1.x format. */
2169 #if 0 /* defined( MINGW ) */
2170 /* mingw32 doesn't have enough headers to detect cygwin
2171 apps, just do what we can. */
2172 FILHDR * exe_header;
2174 exe_header = (FILHDR*) executable.file_base;
2175 if (exe_header->e_magic != DOSMAGIC)
2178 if ((char*) exe_header->e_lfanew > (char*) executable.size)
2180 /* Some dos headers (pkunzip) have bogus e_lfanew fields. */
2183 else if (exe_header->nt_signature != NT_SIGNATURE)
2188 IMAGE_DOS_HEADER * dos_header;
2189 IMAGE_NT_HEADERS * nt_header;
2191 dos_header = (PIMAGE_DOS_HEADER) executable.file_base;
2192 if (dos_header->e_magic != IMAGE_DOS_SIGNATURE)
2195 nt_header = (PIMAGE_NT_HEADERS) ((char*) dos_header + dos_header->e_lfanew);
2197 if ((char*) nt_header > (char*) dos_header + executable.size)
2199 /* Some dos headers (pkunzip) have bogus e_lfanew fields. */
2202 else if (nt_header->Signature != IMAGE_NT_SIGNATURE &&
2203 LOWORD (nt_header->Signature) != IMAGE_OS2_SIGNATURE)
2207 else if (nt_header->Signature == IMAGE_NT_SIGNATURE)
2209 /* Look for cygwin.dll in DLL import list. */
2210 IMAGE_DATA_DIRECTORY import_dir =
2211 nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
2212 IMAGE_IMPORT_DESCRIPTOR * imports;
2213 IMAGE_SECTION_HEADER * section;
2215 section = rva_to_section (import_dir.VirtualAddress, nt_header);
2216 imports = (IMAGE_IMPORT_DESCRIPTOR *) RVA_TO_PTR (import_dir.VirtualAddress,
2217 section, executable);
2219 for ( ; imports->Name; imports++)
2221 char *dllname = (char*) RVA_TO_PTR (imports->Name, section, executable);
2223 /* The exact name of the cygwin dll has changed with
2224 various releases, but hopefully this will be reasonably
2226 if (strncmp (dllname, "cygwin", 6) == 0)
2228 *is_cygnus_app = TRUE;
2237 close_file_data (&executable);
2241 convert_from_time_t (time_t time, FILETIME * pft)
2247 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
2256 st.wMilliseconds = 0;
2258 SystemTimeToFileTime (&st, &utc_base_ft);
2259 utc_base = (long double) utc_base_ft.dwHighDateTime
2260 * 4096 * 1024 * 1024 + utc_base_ft.dwLowDateTime;
2264 /* time in 100ns units since 1-Jan-1601 */
2265 tmp = (long double) time * 1e7 + utc_base;
2266 pft->dwHighDateTime = (DWORD) (tmp / (4096.0 * 1024 * 1024));
2267 pft->dwLowDateTime = (DWORD) (tmp - (4096.0 * 1024 * 1024) *
2268 pft->dwHighDateTime);
2272 mswindows_utime (Lisp_Object path, struct utimbuf *times)
2274 struct utimbuf deftime;
2278 static FILETIME mtime;
2279 static FILETIME atime;
2284 deftime.modtime = deftime.actime = time (NULL);
2288 LISP_STRING_TO_EXTERNAL (path, filename, Qmswindows_tstr);
2289 /* APA: SetFileTime fails to set mtime correctly (always 1-Jan-1970) */
2291 /* Need write access to set times. */
2292 fh = CreateFile (filename, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
2293 0, OPEN_EXISTING, 0, NULL);
2296 convert_from_time_t (times->actime, &atime);
2297 convert_from_time_t (times->modtime, &mtime);
2298 if (!SetFileTime (fh, NULL, &atime, &mtime))
2313 return utime (filename, times);
2317 /* Close the system structures associated with the given file. */
2319 close_file_data (file_data *p_file)
2321 UnmapViewOfFile (p_file->file_base);
2322 CloseHandle (p_file->file_mapping);
2323 CloseHandle (p_file->file);
2329 DEFVAR_INT ("nt-fake-unix-uid", &nt_fake_unix_uid /*
2330 *Set uid returned by `user-uid' and `user-real-uid'.
2331 Under NT and 9x, there is no uids, and even no almighty user called root.
2332 By setting this variable, you can have any uid of choice. Default is 0.
2333 Changes to this variable take effect immediately.
2335 nt_fake_unix_uid = 0;