1 /* Utility and Unix shadow routines for XEmacs on Windows NT.
2 Copyright (C) 1994, 1995 Free Software Foundation, Inc.
4 This file is part of XEmacs.
6 XEmacs is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 XEmacs is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 You should have received a copy of the GNU General Public License
17 along with XEmacs; see the file COPYING. If not, write to the Free
18 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
22 Geoff Voelker (voelker@cs.washington.edu) 7-29-94 */
24 /* Adapted for XEmacs by David Hobley <david@spook-le0.cia.com.au> */
25 /* Sync'ed with Emacs 19.34.6 by Marc Paquette <marcpa@cam.org> */
35 #include "syssignal.h"
46 #include <stddef.h> /* for offsetof */
55 typedef void (CALLBACK TIMECALLBACK)(UINT uTimerID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2);
57 typedef TIMECALLBACK FAR *LPTIMECALLBACK;
58 DWORD WINAPI timeGetTime(void);
59 MMRESULT WINAPI timeSetEvent(UINT uDelay, UINT uResolution,
60 LPTIMECALLBACK fptc, DWORD dwUser, UINT fuEvent);
61 MMRESULT WINAPI timeKillEvent(UINT uTimerID);
62 MMRESULT WINAPI timeGetDevCaps(TIMECAPS* ptc, UINT cbtc);
63 MMRESULT WINAPI timeBeginPeriod(UINT uPeriod);
64 MMRESULT WINAPI timeEndPeriod(UINT uPeriod);
72 extern Lisp_Object Vmswindows_downcase_file_names;
74 extern Lisp_Object Vwin32_generate_fake_inodes;
76 extern Lisp_Object Vmswindows_get_true_file_attributes;
78 extern char *get_home_directory(void);
80 static char startup_dir[ MAXPATHLEN ];
82 /* Get the current working directory. */
87 if (GetCurrentDirectory (MAXPATHLEN, dir) > 0)
91 /* Emacs doesn't actually change directory itself, and we want to
92 force our real wd to be where emacs.exe is to avoid unnecessary
93 conflicts when trying to rename or delete directories. */
94 strcpy (dir, startup_dir);
99 /* Emulate getloadavg. */
101 getloadavg (double loadavg[], int nelem)
105 /* A faithful emulation is going to have to be saved for a rainy day. */
106 for (i = 0; i < nelem; i++)
113 /* Emulate getpwuid, getpwnam and others. */
115 #define PASSWD_FIELD_SIZE 256
117 static char the_passwd_name[PASSWD_FIELD_SIZE];
118 static char the_passwd_passwd[PASSWD_FIELD_SIZE];
119 static char the_passwd_gecos[PASSWD_FIELD_SIZE];
120 static char the_passwd_dir[PASSWD_FIELD_SIZE];
121 static char the_passwd_shell[PASSWD_FIELD_SIZE];
123 static struct passwd the_passwd =
138 return the_passwd.pw_uid;
144 /* I could imagine arguing for checking to see whether the user is
145 in the Administrators group and returning a UID of 0 for that
146 case, but I don't know how wise that would be in the long run. */
153 return the_passwd.pw_gid;
165 if (uid == the_passwd.pw_uid)
171 getpwnam (const char *name)
175 pw = getpwuid (getuid ());
179 if (stricmp (name, pw->pw_name))
188 /* Find the user's real name by opening the process token and
189 looking up the name associated with the user-sid in that token.
191 Use the relative portion of the identifier authority value from
192 the user-sid as the user id value (same for group id using the
193 primary group sid from the process token). */
195 char user_sid[256], name[256], domain[256];
196 DWORD length = sizeof (name), dlength = sizeof (domain), trash;
198 SID_NAME_USE user_type;
200 if (OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY, &token)
201 && GetTokenInformation (token, TokenUser,
202 (PVOID) user_sid, sizeof (user_sid), &trash)
203 && LookupAccountSid (NULL, *((PSID *) user_sid), name, &length,
204 domain, &dlength, &user_type))
206 strcpy (the_passwd.pw_name, name);
207 /* Determine a reasonable uid value. */
208 if (stricmp ("administrator", name) == 0)
210 the_passwd.pw_uid = 0;
211 the_passwd.pw_gid = 0;
215 SID_IDENTIFIER_AUTHORITY * pSIA;
217 pSIA = GetSidIdentifierAuthority (*((PSID *) user_sid));
218 /* I believe the relative portion is the last 4 bytes (of 6)
220 the_passwd.pw_uid = ((pSIA->Value[2] << 24) +
221 (pSIA->Value[3] << 16) +
222 (pSIA->Value[4] << 8) +
223 (pSIA->Value[5] << 0));
224 /* restrict to conventional uid range for normal users */
225 the_passwd.pw_uid = the_passwd.pw_uid % 60001;
228 if (GetTokenInformation (token, TokenPrimaryGroup,
229 (PVOID) user_sid, sizeof (user_sid), &trash))
231 SID_IDENTIFIER_AUTHORITY * pSIA;
233 pSIA = GetSidIdentifierAuthority (*((PSID *) user_sid));
234 the_passwd.pw_gid = ((pSIA->Value[2] << 24) +
235 (pSIA->Value[3] << 16) +
236 (pSIA->Value[4] << 8) +
237 (pSIA->Value[5] << 0));
238 /* I don't know if this is necessary, but for safety... */
239 the_passwd.pw_gid = the_passwd.pw_gid % 60001;
242 the_passwd.pw_gid = the_passwd.pw_uid;
245 /* If security calls are not supported (presumably because we
246 are running under Windows 95), fallback to this. */
247 else if (GetUserName (name, &length))
249 strcpy (the_passwd.pw_name, name);
250 if (stricmp ("administrator", name) == 0)
251 the_passwd.pw_uid = 0;
253 the_passwd.pw_uid = 123;
254 the_passwd.pw_gid = the_passwd.pw_uid;
258 strcpy (the_passwd.pw_name, "unknown");
259 the_passwd.pw_uid = 123;
260 the_passwd.pw_gid = 123;
263 /* Ensure HOME and SHELL are defined. */
266 * With XEmacs, setting $HOME is deprecated.
268 if (getenv ("HOME") == NULL)
271 if (getenv ("SHELL") == NULL)
272 putenv ((GetVersion () & 0x80000000) ? "SHELL=command" : "SHELL=cmd");
274 /* Set dir and shell from environment variables. */
275 strcpy (the_passwd.pw_dir, get_home_directory());
276 strcpy (the_passwd.pw_shell, getenv ("SHELL"));
282 /* Normalize filename by converting all path separators to
283 the specified separator. Also conditionally convert upper
284 case path name components to lower case. */
287 normalize_filename (fp, path_sep)
294 /* Always lower-case drive letters a-z, even if the filesystem
295 preserves case in filenames.
296 This is so filenames can be compared by string comparison
297 functions that are case-sensitive. Even case-preserving filesystems
298 do not distinguish case in drive letters. */
299 if (fp[1] == ':' && *fp >= 'A' && *fp <= 'Z')
305 if (NILP (Vmswindows_downcase_file_names))
309 if (*fp == '/' || *fp == '\\')
316 sep = path_sep; /* convert to this path separator */
317 elem = fp; /* start of current path element */
320 if (*fp >= 'a' && *fp <= 'z')
321 elem = 0; /* don't convert this element */
323 if (*fp == 0 || *fp == ':')
325 sep = *fp; /* restore current separator (or 0) */
326 *fp = '/'; /* after conversion of this element */
329 if (*fp == '/' || *fp == '\\')
331 if (elem && elem != fp)
333 *fp = 0; /* temporary end of string */
334 _strlwr (elem); /* while we convert to lower case */
336 *fp = sep; /* convert (or restore) path separator */
337 elem = fp + 1; /* next element starts after separator */
343 /* Destructively turn backslashes into slashes. */
345 dostounix_filename (p)
348 normalize_filename (p, '/');
351 /* Destructively turn slashes into backslashes. */
353 unixtodos_filename (p)
356 normalize_filename (p, '\\');
359 /* Remove all CR's that are followed by a LF.
360 (From msdos.c...probably should figure out a way to share it,
361 although this code isn't going to ever change.) */
363 crlf_to_lf (n, buf, lf_count)
365 REGISTER unsigned char *buf;
366 REGISTER unsigned *lf_count;
368 unsigned char *np = buf;
369 unsigned char *startp = buf;
370 unsigned char *endp = buf + n;
374 while (buf < endp - 1)
380 if (*(++buf) != 0x0a)
395 /* Parse the root part of file name, if present. Return length and
396 optionally store pointer to char after root. */
398 parse_root (char * name, char ** pPath)
405 /* find the root name of the volume if given */
406 if (isalpha (name[0]) && name[1] == ':')
408 /* skip past drive specifier */
410 if (IS_DIRECTORY_SEP (name[0]))
413 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
419 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
424 if (IS_DIRECTORY_SEP (name[0]))
434 /* Get long base name for name; name is assumed to be absolute. */
436 get_long_basename (char * name, char * buf, int size)
438 WIN32_FIND_DATA find_data;
444 /* If the last component of NAME has a wildcard character,
445 return it as the basename. */
446 p = name + strlen (name);
447 while (*p != '\\' && *p != ':' && p > name) p--;
449 if (strchr (p, '*') || strchr (p, '?'))
451 if ((len = strlen (p)) < size)
452 memcpy (buf, p, len + 1);
459 dir_handle = FindFirstFile (name, &find_data);
460 if (dir_handle != INVALID_HANDLE_VALUE)
462 if ((len = strlen (find_data.cFileName)) < size)
463 memcpy (buf, find_data.cFileName, len + 1);
466 FindClose (dir_handle);
471 /* Get long name for file, if possible (assumed to be absolute). */
473 win32_get_long_filename (char * name, char * buf, int size)
478 char full[ MAX_PATH ];
485 /* Use local copy for destructive modification. */
486 memcpy (full, name, len+1);
487 unixtodos_filename (full);
489 /* Copy root part verbatim. */
490 len = parse_root (full, &p);
491 memcpy (o, full, len);
498 p = strchr (q, '\\');
500 len = get_long_basename (full, o, size);
518 while (p != NULL && *p);
524 /* Routines that are no-ops on NT but are defined to get Emacs to compile. */
526 #if 0 /* #### We do not need those, do we? -kkm */
528 unrequest_sigio (void)
540 #define REG_ROOT "SOFTWARE\\GNU\\XEmacs"
543 nt_get_resource (key, lpdwtype)
548 HKEY hrootkey = NULL;
551 /* Check both the current user and the local machine to see if
552 we have any resources. */
554 if (RegOpenKeyEx (HKEY_CURRENT_USER, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
558 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
559 && (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL
560 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
565 if (lpvalue) xfree (lpvalue);
567 RegCloseKey (hrootkey);
570 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
574 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS &&
575 (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL &&
576 RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
581 if (lpvalue) xfree (lpvalue);
583 RegCloseKey (hrootkey);
592 /* Check for environment variables and use registry if they don't exist */
598 static char * env_vars[] =
613 for (i = 0; i < countof (env_vars); i++)
615 if (!getenv (env_vars[i]) &&
616 (lpval = nt_get_resource (env_vars[i], &dwType)) != NULL)
618 if (dwType == REG_EXPAND_SZ)
620 char buf1[500], buf2[500];
622 ExpandEnvironmentStrings ((LPSTR) lpval, buf1, 500);
623 _snprintf (buf2, 499, "%s=%s", env_vars[i], buf1);
624 putenv (strdup (buf2));
626 else if (dwType == REG_SZ)
630 _snprintf (buf, 499, "%s=%s", env_vars[i], lpval);
631 putenv (strdup (buf));
639 /* Another special case: on NT, the PATH variable is actually named
640 "Path" although cmd.exe (perhaps NT itself) arranges for
641 environment variable lookup and setting to be case insensitive.
642 However, Emacs assumes a fully case sensitive environment, so we
643 need to change "Path" to "PATH" to match the expectations of
644 various elisp packages. We do this by the sneaky method of
645 modifying the string in the C runtime environ entry.
647 The same applies to COMSPEC. */
651 for (envp = environ; *envp; envp++)
652 if (_strnicmp (*envp, "PATH=", 5) == 0)
653 memcpy (*envp, "PATH=", 5);
654 else if (_strnicmp (*envp, "COMSPEC=", 8) == 0)
655 memcpy (*envp, "COMSPEC=", 8);
658 /* Remember the initial working directory for getwd, then make the
659 real wd be the location of emacs.exe to avoid conflicts when
660 renaming or deleting directories. (We also don't call chdir when
661 running subprocesses for the same reason.) */
662 if (!GetCurrentDirectory (MAXPATHLEN, startup_dir))
667 char modname[MAX_PATH];
669 if (!GetModuleFileName (NULL, modname, MAX_PATH))
671 if ((p = strrchr (modname, '\\')) == NULL)
675 SetCurrentDirectory (modname);
681 #ifndef HAVE_X_WINDOWS
682 /* X11R6 on NT provides the single parameter version of this command. */
684 #include <sys/timeb.h>
686 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
688 gettimeofday (struct timeval *tv, struct timezone *tz)
693 tv->tv_sec = tb.time;
694 tv->tv_usec = tb.millitm * 1000L;
697 tz->tz_minuteswest = tb.timezone; /* minutes west of Greenwich */
698 tz->tz_dsttime = tb.dstflag; /* type of dst correction */
702 #endif /* HAVE_X_WINDOWS */
704 /* ------------------------------------------------------------------------- */
705 /* IO support and wrapper functions for Win32 API. */
706 /* ------------------------------------------------------------------------- */
708 /* Place a wrapper around the MSVC version of ctime. It returns NULL
709 on network directories, so we handle that case here.
710 (Ulrich Leodolter, 1/11/95). */
712 sys_ctime (const time_t *t)
714 char *str = (char *) ctime (t);
715 return (str ? str : "Sun Jan 01 00:00:00 1970");
718 /* Emulate sleep...we could have done this with a define, but that
719 would necessitate including windows.h in the files that used it.
720 This is much easier. */
722 #ifndef HAVE_X_WINDOWS
724 sys_sleep (int seconds)
726 Sleep (seconds * 1000);
730 /* #### This is an evil dirty hack. We must get rid of it.
731 Word "munging" is not in XEmacs lexicon. - kkm */
733 /* Internal MSVC data and functions for low-level descriptor munging */
734 #if (_MSC_VER == 900)
735 extern char _osfile[];
737 extern int __cdecl _set_osfhnd (int fd, long h);
738 extern int __cdecl _free_osfhnd (int fd);
740 /* parallel array of private info on file handles */
741 filedesc fd_info [ MAXDESC ];
743 typedef struct volume_info_data {
744 struct volume_info_data * next;
746 /* time when info was obtained */
749 /* actual volume info */
758 /* Global referenced by various functions. */
759 static volume_info_data volume_info;
761 /* Vector to indicate which drives are local and fixed (for which cached
762 data never expires). */
763 static BOOL fixed_drives[26];
765 /* Consider cached volume information to be stale if older than 10s,
766 at least for non-local drives. Info for fixed drives is never stale. */
767 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
768 #define VOLINFO_STILL_VALID( root_dir, info ) \
769 ( ( isalpha (root_dir[0]) && \
770 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
771 || GetTickCount () - info->timestamp < 10000 )
773 /* Cache support functions. */
775 /* Simple linked list with linear search is sufficient. */
776 static volume_info_data *volume_cache = NULL;
778 static volume_info_data *
779 lookup_volume_info (char * root_dir)
781 volume_info_data * info;
783 for (info = volume_cache; info; info = info->next)
784 if (stricmp (info->root_dir, root_dir) == 0)
790 add_volume_info (char * root_dir, volume_info_data * info)
792 info->root_dir = xstrdup (root_dir);
793 info->next = volume_cache;
798 /* Wrapper for GetVolumeInformation, which uses caching to avoid
799 performance penalty (~2ms on 486 for local drives, 7.5ms for local
800 cdrom drive, ~5-10ms or more for remote drives on LAN). */
802 GetCachedVolumeInformation (char * root_dir)
804 volume_info_data * info;
805 char default_root[ MAX_PATH ];
807 /* NULL for root_dir means use root from current directory. */
808 if (root_dir == NULL)
810 if (GetCurrentDirectory (MAX_PATH, default_root) == 0)
812 parse_root (default_root, &root_dir);
814 root_dir = default_root;
817 /* Local fixed drives can be cached permanently. Removable drives
818 cannot be cached permanently, since the volume name and serial
819 number (if nothing else) can change. Remote drives should be
820 treated as if they are removable, since there is no sure way to
821 tell whether they are or not. Also, the UNC association of drive
822 letters mapped to remote volumes can be changed at any time (even
823 by other processes) without notice.
825 As a compromise, so we can benefit from caching info for remote
826 volumes, we use a simple expiry mechanism to invalidate cache
827 entries that are more than ten seconds old. */
830 /* No point doing this, because WNetGetConnection is even slower than
831 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
832 GetDriveType is about the only call of this type which does not
833 involve network access, and so is extremely quick). */
835 /* Map drive letter to UNC if remote. */
836 if ( isalpha( root_dir[0] ) && !fixed[ DRIVE_INDEX( root_dir[0] ) ] )
838 char remote_name[ 256 ];
839 char drive[3] = { root_dir[0], ':' };
841 if (WNetGetConnection (drive, remote_name, sizeof (remote_name))
847 info = lookup_volume_info (root_dir);
849 if (info == NULL || ! VOLINFO_STILL_VALID (root_dir, info))
857 /* Info is not cached, or is stale. */
858 if (!GetVolumeInformation (root_dir,
863 type, sizeof (type)))
866 /* Cache the volume information for future use, overwriting existing
870 info = (volume_info_data *) xmalloc (sizeof (volume_info_data));
871 add_volume_info (root_dir, info);
879 info->name = xstrdup (name);
880 info->serialnum = serialnum;
881 info->maxcomp = maxcomp;
883 info->type = xstrdup (type);
884 info->timestamp = GetTickCount ();
890 /* Get information on the volume where name is held; set path pointer to
891 start of pathname in name (past UNC header\volume header if present). */
893 get_volume_info (const char * name, const char ** pPath)
896 char *rootname = NULL; /* default to current volume */
897 volume_info_data * info;
902 /* find the root name of the volume if given */
903 if (isalpha (name[0]) && name[1] == ':')
911 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
918 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
931 info = GetCachedVolumeInformation (rootname);
934 /* Set global referenced by other functions. */
941 /* Determine if volume is FAT format (ie. only supports short 8.3
942 names); also set path pointer to start of pathname in name. */
944 is_fat_volume (const char * name, const char ** pPath)
946 if (get_volume_info (name, pPath))
947 return (volume_info.maxcomp == 12);
951 /* Map filename to a legal 8.3 name if necessary. */
953 map_win32_filename (const char * name, const char ** pPath)
955 static char shortname[MAX_PATH];
956 char * str = shortname;
959 const char * save_name = name;
961 if (is_fat_volume (name, &path)) /* truncate to 8.3 */
963 REGISTER int left = 8; /* maximum number of chars in part */
964 REGISTER int extn = 0; /* extension added? */
965 REGISTER int dots = 2; /* maximum number of dots allowed */
968 *str++ = *name++; /* skip past UNC header */
970 while ((c = *name++))
977 extn = 0; /* reset extension flags */
978 dots = 2; /* max 2 dots */
979 left = 8; /* max length 8 for main part */
983 extn = 0; /* reset extension flags */
984 dots = 2; /* max 2 dots */
985 left = 8; /* max length 8 for main part */
990 /* Convert path components of the form .xxx to _xxx,
991 but leave . and .. as they are. This allows .emacs
992 to be read as _emacs, for example. */
996 IS_DIRECTORY_SEP (*name))
1011 extn = 1; /* we've got an extension */
1012 left = 3; /* 3 chars in extension */
1016 /* any embedded dots after the first are converted to _ */
1021 case '#': /* don't lose these, they're important */
1023 str[-1] = c; /* replace last character of part */
1028 *str++ = tolower (c); /* map to lower case (looks nicer) */
1030 dots = 0; /* started a path component */
1039 strcpy (shortname, name);
1040 unixtodos_filename (shortname);
1044 *pPath = shortname + (path - save_name);
1050 /* Emulate the Unix directory procedures opendir, closedir,
1051 and readdir. We can't use the procedures supplied in sysdep.c,
1052 so we provide them here. */
1054 struct direct dir_static; /* simulated directory contents */
1055 static HANDLE dir_find_handle = INVALID_HANDLE_VALUE;
1056 static int dir_is_fat;
1057 static char dir_pathname[MAXPATHLEN+1];
1058 static WIN32_FIND_DATA dir_find_data;
1061 opendir (const char *filename)
1065 /* Opening is done by FindFirstFile. However, a read is inherent to
1066 this operation, so we defer the open until read time. */
1068 if (!(dirp = xnew_and_zero(DIR)))
1070 if (dir_find_handle != INVALID_HANDLE_VALUE)
1077 strncpy (dir_pathname, map_win32_filename (filename, NULL), MAXPATHLEN);
1078 dir_pathname[MAXPATHLEN] = '\0';
1079 dir_is_fat = is_fat_volume (filename, NULL);
1085 closedir (DIR *dirp)
1087 /* If we have a find-handle open, close it. */
1088 if (dir_find_handle != INVALID_HANDLE_VALUE)
1090 FindClose (dir_find_handle);
1091 dir_find_handle = INVALID_HANDLE_VALUE;
1099 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
1100 if (dir_find_handle == INVALID_HANDLE_VALUE)
1102 char filename[MAXNAMLEN + 3];
1105 strcpy (filename, dir_pathname);
1106 ln = strlen (filename) - 1;
1107 if (!IS_DIRECTORY_SEP (filename[ln]))
1108 strcat (filename, "\\");
1109 strcat (filename, "*");
1111 dir_find_handle = FindFirstFile (filename, &dir_find_data);
1113 if (dir_find_handle == INVALID_HANDLE_VALUE)
1118 if (!FindNextFile (dir_find_handle, &dir_find_data))
1122 /* Emacs never uses this value, so don't bother making it match
1123 value returned by stat(). */
1124 dir_static.d_ino = 1;
1126 dir_static.d_reclen = sizeof (struct direct) - MAXNAMLEN + 3 +
1127 dir_static.d_namlen - dir_static.d_namlen % 4;
1129 dir_static.d_namlen = strlen (dir_find_data.cFileName);
1130 strcpy (dir_static.d_name, dir_find_data.cFileName);
1132 _strlwr (dir_static.d_name);
1133 else if (!NILP (Vmswindows_downcase_file_names))
1136 for (p = dir_static.d_name; *p; p++)
1137 if (*p >= 'a' && *p <= 'z')
1140 _strlwr (dir_static.d_name);
1147 /* #### Have to check if all that sad story about '95 is true - kkm */
1149 sys_rename (const char * oldname, const char * newname)
1151 char temp[MAX_PATH];
1154 /* MoveFile on Win95 doesn't correctly change the short file name
1155 alias in a number of circumstances (it is not easy to predict when
1156 just by looking at oldname and newname, unfortunately). In these
1157 cases, renaming through a temporary name avoids the problem.
1159 A second problem on Win95 is that renaming through a temp name when
1160 newname is uppercase fails (the final long name ends up in
1161 lowercase, although the short alias might be uppercase) UNLESS the
1162 long temp name is not 8.3.
1164 So, on Win95 we always rename through a temp name, and we make sure
1165 the temp name has a long extension to ensure correct renaming. */
1167 strcpy (temp, map_win32_filename (oldname, NULL));
1169 if (GetVersion () & 0x80000000)
1173 if (p = strrchr (temp, '\\'))
1177 /* Force temp name to require a manufactured 8.3 alias - this
1178 seems to make the second rename work properly. */
1179 strcpy (p, "_rename_temp.XXXXXX");
1181 if (rename (map_win32_filename (oldname, NULL), temp) < 0)
1185 /* Emulate Unix behavior - newname is deleted if it already exists
1186 (at least if it is a file; don't do this for directories).
1187 However, don't do this if we are just changing the case of the file
1188 name - we will end up deleting the file we are trying to rename! */
1189 newname = map_win32_filename (newname, NULL);
1191 /* TODO: Use GetInformationByHandle (on NT) to ensure newname and temp
1192 do not refer to the same file, eg. through share aliases. */
1193 if (stricmp (newname, temp) != 0
1194 && (attr = GetFileAttributes (newname)) != -1
1195 && (attr & FILE_ATTRIBUTE_DIRECTORY) == 0)
1197 _chmod (newname, 0666);
1201 return rename (temp, newname);
1205 static FILETIME utc_base_ft;
1206 static long double utc_base;
1207 static int init = 0;
1210 convert_time (FILETIME ft)
1216 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
1225 st.wMilliseconds = 0;
1227 SystemTimeToFileTime (&st, &utc_base_ft);
1228 utc_base = (long double) utc_base_ft.dwHighDateTime
1229 * 4096 * 1024 * 1024 + utc_base_ft.dwLowDateTime;
1233 if (CompareFileTime (&ft, &utc_base_ft) < 0)
1236 ret = (long double) ft.dwHighDateTime * 4096 * 1024 * 1024 + ft.dwLowDateTime;
1238 return (time_t) (ret * 1e-7);
1242 /* in case we ever have need of this */
1244 convert_from_time_t (time_t time, FILETIME * pft)
1250 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
1259 st.wMilliseconds = 0;
1261 SystemTimeToFileTime (&st, &utc_base_ft);
1262 utc_base = (long double) utc_base_ft.dwHighDateTime
1263 * 4096 * 1024 * 1024 + utc_base_ft.dwLowDateTime;
1267 /* time in 100ns units since 1-Jan-1601 */
1268 tmp = (long double) time * 1e7 + utc_base;
1269 pft->dwHighDateTime = (DWORD) (tmp / (4096.0 * 1024 * 1024));
1270 pft->dwLowDateTime = (DWORD) (tmp - pft->dwHighDateTime);
1275 /* No reason to keep this; faking inode values either by hashing or even
1276 using the file index from GetInformationByHandle, is not perfect and
1277 so by default Emacs doesn't use the inode values on Windows.
1278 Instead, we now determine file-truename correctly (except for
1279 possible drive aliasing etc). */
1281 /* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
1283 hashval (const unsigned char * str)
1288 h = (h << 4) + *str++;
1294 /* Return the hash value of the canonical pathname, excluding the
1295 drive/UNC header, to get a hopefully unique inode number. */
1297 generate_inode_val (const char * name)
1299 char fullname[ MAX_PATH ];
1303 /* Get the truly canonical filename, if it exists. (Note: this
1304 doesn't resolve aliasing due to subst commands, or recognize hard
1306 if (!win32_get_long_filename ((char *)name, fullname, MAX_PATH))
1309 parse_root (fullname, &p);
1310 /* Normal Win32 filesystems are still case insensitive. */
1317 /* MSVC stat function can't cope with UNC names and has other bugs, so
1318 replace it with our own. This also allows us to calculate consistent
1319 inode values without hacks in the main Emacs code. */
1321 stat (const char * path, struct stat * buf)
1324 WIN32_FIND_DATA wfd;
1329 int rootdir = FALSE;
1331 if (path == NULL || buf == NULL)
1337 name = (char *) map_win32_filename (path, &path);
1338 /* must be valid filename, no wild cards */
1339 if (strchr (name, '*') || strchr (name, '?'))
1345 /* Remove trailing directory separator, unless name is the root
1346 directory of a drive or UNC volume in which case ensure there
1347 is a trailing separator. */
1348 len = strlen (name);
1349 rootdir = (path >= name + len - 1
1350 && (IS_DIRECTORY_SEP (*path) || *path == 0));
1351 name = strcpy (alloca (len + 2), name);
1355 if (!IS_DIRECTORY_SEP (name[len-1]))
1356 strcat (name, "\\");
1357 if (GetDriveType (name) < 2)
1362 memset (&wfd, 0, sizeof (wfd));
1363 wfd.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
1364 wfd.ftCreationTime = utc_base_ft;
1365 wfd.ftLastAccessTime = utc_base_ft;
1366 wfd.ftLastWriteTime = utc_base_ft;
1367 strcpy (wfd.cFileName, name);
1371 if (IS_DIRECTORY_SEP (name[len-1]))
1374 /* (This is hacky, but helps when doing file completions on
1375 network drives.) Optimize by using information available from
1376 active readdir if possible. */
1377 if (dir_find_handle != INVALID_HANDLE_VALUE &&
1378 (len = strlen (dir_pathname)),
1379 strnicmp (name, dir_pathname, len) == 0 &&
1380 IS_DIRECTORY_SEP (name[len]) &&
1381 stricmp (name + len + 1, dir_static.d_name) == 0)
1383 /* This was the last entry returned by readdir. */
1384 wfd = dir_find_data;
1388 fh = FindFirstFile (name, &wfd);
1389 if (fh == INVALID_HANDLE_VALUE)
1398 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1400 buf->st_mode = _S_IFDIR;
1401 buf->st_nlink = 2; /* doesn't really matter */
1402 fake_inode = 0; /* this doesn't either I think */
1404 else if (!NILP (Vmswindows_get_true_file_attributes))
1406 /* This is more accurate in terms of getting the correct number
1407 of links, but is quite slow (it is noticeable when Emacs is
1408 making a list of file name completions). */
1409 BY_HANDLE_FILE_INFORMATION info;
1411 /* No access rights required to get info. */
1412 fh = CreateFile (name, 0, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
1413 OPEN_EXISTING, 0, NULL);
1415 if (GetFileInformationByHandle (fh, &info))
1417 switch (GetFileType (fh))
1419 case FILE_TYPE_DISK:
1420 buf->st_mode = _S_IFREG;
1422 case FILE_TYPE_PIPE:
1423 buf->st_mode = _S_IFIFO;
1425 case FILE_TYPE_CHAR:
1426 case FILE_TYPE_UNKNOWN:
1428 buf->st_mode = _S_IFCHR;
1430 buf->st_nlink = (short) info.nNumberOfLinks;
1431 /* Might as well use file index to fake inode values, but this
1432 is not guaranteed to be unique unless we keep a handle open
1433 all the time (even then there are situations where it is
1434 not unique). Reputedly, there are at most 48 bits of info
1435 (on NTFS, presumably less on FAT). */
1436 fake_inode = info.nFileIndexLow ^ info.nFileIndexHigh;
1447 /* Don't bother to make this information more accurate. */
1448 buf->st_mode = _S_IFREG;
1454 /* Not sure if there is any point in this. */
1455 if (!NILP (Vwin32_generate_fake_inodes))
1456 fake_inode = generate_inode_val (name);
1457 else if (fake_inode == 0)
1459 /* For want of something better, try to make everything unique. */
1460 static DWORD gen_num = 0;
1461 fake_inode = ++gen_num;
1465 /* #### MSVC defines _ino_t to be short; other libc's might not. */
1466 buf->st_ino = (unsigned short) (fake_inode ^ (fake_inode >> 16));
1468 /* consider files to belong to current user */
1469 buf->st_uid = the_passwd.pw_uid;
1470 buf->st_gid = the_passwd.pw_gid;
1472 /* volume_info is set indirectly by map_win32_filename */
1473 buf->st_dev = volume_info.serialnum;
1474 buf->st_rdev = volume_info.serialnum;
1477 buf->st_size = wfd.nFileSizeLow;
1479 /* Convert timestamps to Unix format. */
1480 buf->st_mtime = convert_time (wfd.ftLastWriteTime);
1481 buf->st_atime = convert_time (wfd.ftLastAccessTime);
1482 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
1483 buf->st_ctime = convert_time (wfd.ftCreationTime);
1484 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
1486 /* determine rwx permissions */
1487 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
1488 permission = _S_IREAD;
1490 permission = _S_IREAD | _S_IWRITE;
1492 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1493 permission |= _S_IEXEC;
1496 char * p = strrchr (name, '.');
1498 (stricmp (p, ".exe") == 0 ||
1499 stricmp (p, ".com") == 0 ||
1500 stricmp (p, ".bat") == 0 ||
1501 stricmp (p, ".cmd") == 0))
1502 permission |= _S_IEXEC;
1505 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
1510 /* From callproc.c */
1511 extern Lisp_Object Vbinary_process_input;
1512 extern Lisp_Object Vbinary_process_output;
1514 /* Unix pipe() has only one arg */
1516 sys_pipe (int * phandles)
1521 /* make pipe handles non-inheritable; when we spawn a child, we
1522 replace the relevant handle with an inheritable one. Also put
1523 pipes into binary mode; we will do text mode translation ourselves
1525 rc = _pipe (phandles, 0, _O_NOINHERIT | _O_BINARY);
1529 flags = FILE_PIPE | FILE_READ;
1530 if (!NILP (Vbinary_process_output))
1531 flags |= FILE_BINARY;
1532 fd_info[phandles[0]].flags = flags;
1534 flags = FILE_PIPE | FILE_WRITE;
1535 if (!NILP (Vbinary_process_input))
1536 flags |= FILE_BINARY;
1537 fd_info[phandles[1]].flags = flags;
1544 term_ntproc (int unused)
1551 /* Initial preparation for subprocess support: replace our standard
1552 handles with non-inheritable versions. */
1555 HANDLE stdin_save = INVALID_HANDLE_VALUE;
1556 HANDLE stdout_save = INVALID_HANDLE_VALUE;
1557 HANDLE stderr_save = INVALID_HANDLE_VALUE;
1559 parent = GetCurrentProcess ();
1561 /* ignore errors when duplicating and closing; typically the
1562 handles will be invalid when running as a gui program. */
1563 DuplicateHandle (parent,
1564 GetStdHandle (STD_INPUT_HANDLE),
1569 DUPLICATE_SAME_ACCESS);
1571 DuplicateHandle (parent,
1572 GetStdHandle (STD_OUTPUT_HANDLE),
1577 DUPLICATE_SAME_ACCESS);
1579 DuplicateHandle (parent,
1580 GetStdHandle (STD_ERROR_HANDLE),
1585 DUPLICATE_SAME_ACCESS);
1591 if (stdin_save != INVALID_HANDLE_VALUE)
1592 _open_osfhandle ((long) stdin_save, O_TEXT);
1594 _open ("nul", O_TEXT | O_NOINHERIT | O_RDONLY);
1597 if (stdout_save != INVALID_HANDLE_VALUE)
1598 _open_osfhandle ((long) stdout_save, O_TEXT);
1600 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
1603 if (stderr_save != INVALID_HANDLE_VALUE)
1604 _open_osfhandle ((long) stderr_save, O_TEXT);
1606 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
1610 /* unfortunately, atexit depends on implementation of malloc */
1611 /* atexit (term_ntproc); */
1612 signal (SIGABRT, term_ntproc);
1614 /* determine which drives are fixed, for GetCachedVolumeInformation */
1616 /* GetDriveType must have trailing backslash. */
1617 char drive[] = "A:\\";
1619 /* Loop over all possible drive letters */
1620 while ( *drive <= 'Z' )
1622 /* Record if this drive letter refers to a fixed drive. */
1623 fixed_drives[ DRIVE_INDEX (*drive) ] =
1624 (GetDriveType (drive) == DRIVE_FIXED);
1632 tty_semi_canonicalize_console_connection (Lisp_Object connection,
1633 Error_behavior errb)
1639 tty_canonicalize_console_connection (Lisp_Object connection,
1640 Error_behavior errb)
1646 tty_semi_canonicalize_device_connection (Lisp_Object connection,
1647 Error_behavior errb)
1653 tty_canonicalize_device_connection (Lisp_Object connection,
1654 Error_behavior errb)
1660 /*--------------------------------------------------------------------*/
1661 /* Signal support */
1662 /*--------------------------------------------------------------------*/
1664 /* We need MS-defined signal and raise here */
1668 #define sigmask(nsig) (1U << nsig)
1670 /* We can support as many signals as fit into word */
1673 /* Signal handlers. Initial value = 0 = SIG_DFL */
1674 static void (__cdecl *signal_handlers[SIG_MAX])(int) = {0};
1676 /* Signal block mask: bit set to 1 means blocked */
1677 unsigned signal_block_mask = 0;
1679 /* Signal pending mask: bit set to 1 means sig is pending */
1680 unsigned signal_pending_mask = 0;
1682 msw_sighandler msw_sigset (int nsig, msw_sighandler handler)
1684 /* We delegate some signals to the system function */
1685 if (nsig == SIGFPE || nsig == SIGABRT || nsig == SIGINT)
1686 return signal (nsig, handler);
1688 if (nsig < 0 || nsig > SIG_MAX)
1694 /* Store handler ptr */
1696 msw_sighandler old_handler = signal_handlers[nsig];
1697 signal_handlers[nsig] = handler;
1702 int msw_sighold (int nsig)
1704 if (nsig < 0 || nsig > SIG_MAX)
1705 return errno = EINVAL;
1707 signal_block_mask |= sigmask(nsig);
1711 int msw_sigrelse (int nsig)
1713 if (nsig < 0 || nsig > SIG_MAX)
1714 return errno = EINVAL;
1716 signal_block_mask &= ~sigmask(nsig);
1718 if (signal_pending_mask & sigmask(nsig))
1724 int msw_sigpause (int nsig)
1726 /* This is currently not called, because the only
1727 call to sigpause inside XEmacs is with SIGCHLD
1728 parameter. Just in case, we put an assert here,
1729 so anyone who will add a call to sigpause will
1730 be surprised (or surprise someone else...) */
1735 int msw_raise (int nsig)
1737 /* We delegate some raises to the system routine */
1738 if (nsig == SIGFPE || nsig == SIGABRT || nsig == SIGINT)
1739 return raise (nsig);
1741 if (nsig < 0 || nsig > SIG_MAX)
1742 return errno = EINVAL;
1744 /* If the signal is blocked, remember to issue later */
1745 if (signal_block_mask & sigmask(nsig))
1747 signal_pending_mask |= sigmask(nsig);
1751 if (signal_handlers[nsig] == SIG_IGN)
1754 if (signal_handlers[nsig] != SIG_DFL)
1756 (*signal_handlers[nsig])(nsig);
1760 /* Default signal actions */
1761 if (nsig == SIGALRM || nsig == SIGPROF)
1764 /* Other signals are ignored by default */
1768 /*--------------------------------------------------------------------*/
1770 /*--------------------------------------------------------------------*/
1772 /* We emulate two timers, one for SIGALRM, another for SIGPROF.
1774 itimerproc() function has an implementation limitation: it does
1775 not allow to set *both* interval and period. If an attempt is
1776 made to set both, and then they are unequal, the function
1779 Minimum timer resolution on Win32 systems varies, and is greater
1780 than or equal than 1 ms. The resolution is always wrapped not to
1781 attempt to get below the system defined limit.
1784 /* Timer precision, denominator of one fraction: for 100 ms
1785 interval, request 10 ms precision
1787 const int timer_prec = 10;
1789 /* Last itimervals, as set by calls to setitimer */
1790 static struct itimerval it_alarm;
1791 static struct itimerval it_prof;
1793 /* Timer IDs as returned by MM */
1794 MMRESULT tid_alarm = 0;
1795 MMRESULT tid_prof = 0;
1797 static void CALLBACK timer_proc (UINT uID, UINT uMsg, DWORD dwUser,
1798 DWORD dw1, DWORD dw2)
1800 /* Just raise a signal indicated by dwUser parameter */
1804 /* Divide time in ms specified by IT by DENOM. Return 1 ms
1805 if division results in zero */
1806 static UINT period (const struct itimerval* it, UINT denom)
1808 static TIMECAPS time_caps;
1811 const struct timeval* tv =
1812 (it->it_value.tv_sec == 0 && it->it_value.tv_usec == 0)
1813 ? &it->it_interval : &it->it_value;
1815 /* Zero means stop timer */
1816 if (tv->tv_sec == 0 && tv->tv_usec == 0)
1819 /* Convert to ms and divide by denom */
1820 res = (tv->tv_sec * 1000 + (tv->tv_usec + 500) / 1000) / denom;
1822 /* Converge to minimum timer resolution */
1823 if (time_caps.wPeriodMin == 0)
1824 timeGetDevCaps (&time_caps, sizeof(time_caps));
1826 if (res < time_caps.wPeriodMin)
1827 res = time_caps.wPeriodMin;
1832 static int setitimer_helper (const struct itimerval* itnew,
1833 struct itimerval* itold, struct itimerval* itcurrent,
1834 MMRESULT* tid, DWORD sigkind)
1836 UINT delay, resolution, event_type;
1838 /* First stop the old timer */
1841 timeKillEvent (*tid);
1842 timeEndPeriod (period (itcurrent, timer_prec));
1846 /* Return old itimerval if requested */
1848 *itold = *itcurrent;
1850 *itcurrent = *itnew;
1852 /* Determine if to start new timer */
1853 delay = period (itnew, 1);
1856 resolution = period (itnew, timer_prec);
1857 event_type = (itnew->it_value.tv_sec == 0 && itnew->it_value.tv_usec == 0)
1858 ? TIME_ONESHOT : TIME_PERIODIC;
1859 timeBeginPeriod (resolution);
1860 *tid = timeSetEvent (delay, resolution, timer_proc, sigkind, event_type);
1863 return !delay || *tid;
1866 int setitimer (int kind, const struct itimerval* itnew,
1867 struct itimerval* itold)
1869 /* In this version, both interval and value are allowed
1870 only if they are equal. */
1871 assert ((itnew->it_value.tv_sec == 0 && itnew->it_value.tv_usec == 0)
1872 || (itnew->it_interval.tv_sec == 0 && itnew->it_interval.tv_usec == 0)
1873 || (itnew->it_value.tv_sec == itnew->it_interval.tv_sec &&
1874 itnew->it_value.tv_usec == itnew->it_interval.tv_usec));
1876 if (kind == ITIMER_REAL)
1877 return setitimer_helper (itnew, itold, &it_alarm, &tid_alarm, SIGALRM);
1878 else if (kind == ITIMER_PROF)
1879 return setitimer_helper (itnew, itold, &it_prof, &tid_prof, SIGPROF);
1881 return errno = EINVAL;
1885 open_input_file (file_data *p_file, CONST char *filename)
1888 HANDLE file_mapping;
1890 DWORD size, upper_size;
1892 file = CreateFile (filename, GENERIC_READ, FILE_SHARE_READ, NULL,
1893 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
1894 if (file == INVALID_HANDLE_VALUE)
1897 size = GetFileSize (file, &upper_size);
1898 file_mapping = CreateFileMapping (file, NULL, PAGE_READONLY,
1903 file_base = MapViewOfFile (file_mapping, FILE_MAP_READ, 0, 0, size);
1907 p_file->name = (char*)filename;
1908 p_file->size = size;
1909 p_file->file = file;
1910 p_file->file_mapping = file_mapping;
1911 p_file->file_base = file_base;
1916 /* Close the system structures associated with the given file. */
1918 close_file_data (file_data *p_file)
1920 UnmapViewOfFile (p_file->file_base);
1921 CloseHandle (p_file->file_mapping);
1922 CloseHandle (p_file->file);