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"
54 typedef void (CALLBACK TIMECALLBACK)(UINT uTimerID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2);
56 typedef TIMECALLBACK FAR *LPTIMECALLBACK;
57 DWORD WINAPI timeGetTime(void);
58 MMRESULT WINAPI timeSetEvent(UINT uDelay, UINT uResolution,
59 LPTIMECALLBACK fptc, DWORD dwUser, UINT fuEvent);
60 MMRESULT WINAPI timeKillEvent(UINT uTimerID);
61 MMRESULT WINAPI timeGetDevCaps(TIMECAPS* ptc, UINT cbtc);
62 MMRESULT WINAPI timeBeginPeriod(UINT uPeriod);
63 MMRESULT WINAPI timeEndPeriod(UINT uPeriod);
71 extern Lisp_Object Vmswindows_downcase_file_names;
73 extern Lisp_Object Vwin32_generate_fake_inodes;
75 extern Lisp_Object Vmswindows_get_true_file_attributes;
79 static char startup_dir[ MAXPATHLEN ];
81 /* Get the current working directory. */
86 if (GetCurrentDirectory (MAXPATHLEN, dir) > 0)
90 /* Emacs doesn't actually change directory itself, and we want to
91 force our real wd to be where emacs.exe is to avoid unnecessary
92 conflicts when trying to rename or delete directories. */
93 strcpy (dir, startup_dir);
98 /* Emulate getloadavg. */
100 getloadavg (double loadavg[], int nelem)
104 /* A faithful emulation is going to have to be saved for a rainy day. */
105 for (i = 0; i < nelem; i++)
112 /* Emulate getpwuid, getpwnam and others. */
114 #define PASSWD_FIELD_SIZE 256
116 static char the_passwd_name[PASSWD_FIELD_SIZE];
117 static char the_passwd_passwd[PASSWD_FIELD_SIZE];
118 static char the_passwd_gecos[PASSWD_FIELD_SIZE];
119 static char the_passwd_dir[PASSWD_FIELD_SIZE];
120 static char the_passwd_shell[PASSWD_FIELD_SIZE];
122 static struct passwd the_passwd =
137 return nt_fake_unix_uid;
143 return nt_fake_unix_uid;
149 return the_passwd.pw_gid;
161 if (uid == nt_fake_unix_uid)
163 the_passwd.pw_gid = the_passwd.pw_uid = uid;
171 getpwnam (const char *name)
175 pw = getpwuid (getuid ());
179 if (stricmp (name, pw->pw_name))
188 /* This code is pretty much of ad hoc nature. There is no unix-like
189 UIDs under Windows NT. There is no concept of root user, because
190 all security is ACL-based. Instead, let's use a simple variable,
191 nt-fake-unix-uid, which would allow the user to have a uid of
192 choice. --kkm, 02/03/2000 */
194 /* Find the user's real name by opening the process token and
195 looking up the name associated with the user-sid in that token.
197 Use the relative portion of the identifier authority value from
198 the user-sid as the user id value (same for group id using the
199 primary group sid from the process token). */
201 char user_sid[256], name[256], domain[256];
202 DWORD length = sizeof (name), dlength = sizeof (domain), trash;
204 SID_NAME_USE user_type;
206 if (OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY, &token)
207 && GetTokenInformation (token, TokenUser,
208 (PVOID) user_sid, sizeof (user_sid), &trash)
209 && LookupAccountSid (NULL, *((PSID *) user_sid), name, &length,
210 domain, &dlength, &user_type))
212 strcpy (the_passwd.pw_name, name);
213 /* Determine a reasonable uid value. */
214 if (stricmp ("administrator", name) == 0)
216 the_passwd.pw_uid = 0;
217 the_passwd.pw_gid = 0;
221 SID_IDENTIFIER_AUTHORITY * pSIA;
223 pSIA = GetSidIdentifierAuthority (*((PSID *) user_sid));
224 /* I believe the relative portion is the last 4 bytes (of 6)
226 the_passwd.pw_uid = ((pSIA->Value[2] << 24) +
227 (pSIA->Value[3] << 16) +
228 (pSIA->Value[4] << 8) +
229 (pSIA->Value[5] << 0));
230 /* restrict to conventional uid range for normal users */
231 the_passwd.pw_uid = the_passwd.pw_uid % 60001;
234 if (GetTokenInformation (token, TokenPrimaryGroup,
235 (PVOID) user_sid, sizeof (user_sid), &trash))
237 SID_IDENTIFIER_AUTHORITY * pSIA;
239 pSIA = GetSidIdentifierAuthority (*((PSID *) user_sid));
240 the_passwd.pw_gid = ((pSIA->Value[2] << 24) +
241 (pSIA->Value[3] << 16) +
242 (pSIA->Value[4] << 8) +
243 (pSIA->Value[5] << 0));
244 /* I don't know if this is necessary, but for safety... */
245 the_passwd.pw_gid = the_passwd.pw_gid % 60001;
248 the_passwd.pw_gid = the_passwd.pw_uid;
251 /* If security calls are not supported (presumably because we
252 are running under Windows 95), fallback to this. */
253 else if (GetUserName (name, &length))
255 strcpy (the_passwd.pw_name, name);
256 if (stricmp ("administrator", name) == 0)
257 the_passwd.pw_uid = 0;
259 the_passwd.pw_uid = 123;
260 the_passwd.pw_gid = the_passwd.pw_uid;
264 strcpy (the_passwd.pw_name, "unknown");
265 the_passwd.pw_uid = 123;
266 the_passwd.pw_gid = 123;
272 /* Obtain only logon id here, uid part is moved to getuid */
274 DWORD length = sizeof (name);
275 if (GetUserName (name, &length))
276 strcpy (the_passwd.pw_name, name);
278 strcpy (the_passwd.pw_name, "unknown");
281 /* Ensure HOME and SHELL are defined. */
284 * With XEmacs, setting $HOME is deprecated.
286 if (getenv ("HOME") == NULL)
289 if (getenv ("SHELL") == NULL)
290 putenv ((GetVersion () & 0x80000000) ? "SHELL=command" : "SHELL=cmd");
292 /* Set dir and shell from environment variables. */
293 strcpy (the_passwd.pw_dir, (char *)get_home_directory());
294 strcpy (the_passwd.pw_shell, getenv ("SHELL"));
297 /* Normalize filename by converting all path separators to
298 the specified separator. Also conditionally convert upper
299 case path name components to lower case. */
302 normalize_filename (char *fp, char path_sep)
307 /* Always lower-case drive letters a-z, even if the filesystem
308 preserves case in filenames.
309 This is so filenames can be compared by string comparison
310 functions that are case-sensitive. Even case-preserving filesystems
311 do not distinguish case in drive letters. */
312 if (fp[1] == ':' && *fp >= 'A' && *fp <= 'Z')
318 if (NILP (Vmswindows_downcase_file_names))
322 if (*fp == '/' || *fp == '\\')
329 sep = path_sep; /* convert to this path separator */
330 elem = fp; /* start of current path element */
333 if (*fp >= 'a' && *fp <= 'z')
334 elem = 0; /* don't convert this element */
336 if (*fp == 0 || *fp == ':')
338 sep = *fp; /* restore current separator (or 0) */
339 *fp = '/'; /* after conversion of this element */
342 if (*fp == '/' || *fp == '\\')
344 if (elem && elem != fp)
346 *fp = 0; /* temporary end of string */
347 _strlwr (elem); /* while we convert to lower case */
349 *fp = sep; /* convert (or restore) path separator */
350 elem = fp + 1; /* next element starts after separator */
356 /* Destructively turn backslashes into slashes. */
358 dostounix_filename (char *p)
360 normalize_filename (p, '/');
363 /* Destructively turn slashes into backslashes. */
365 unixtodos_filename (char *p)
367 normalize_filename (p, '\\');
370 /* Remove all CR's that are followed by a LF.
371 (From msdos.c...probably should figure out a way to share it,
372 although this code isn't going to ever change.) */
374 crlf_to_lf (int n, unsigned char *buf, unsigned *lf_count)
376 unsigned char *np = buf;
377 unsigned char *startp = buf;
378 unsigned char *endp = buf + n;
382 while (buf < endp - 1)
388 if (*(++buf) != 0x0a)
403 /* Parse the root part of file name, if present. Return length and
404 optionally store pointer to char after root. */
406 parse_root (char * name, char ** pPath)
413 /* find the root name of the volume if given */
414 if (isalpha (name[0]) && name[1] == ':')
416 /* skip past drive specifier */
418 if (IS_DIRECTORY_SEP (name[0]))
421 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
427 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
432 if (IS_DIRECTORY_SEP (name[0]))
442 /* Get long base name for name; name is assumed to be absolute. */
444 get_long_basename (char * name, char * buf, int size)
446 WIN32_FIND_DATA find_data;
452 /* If the last component of NAME has a wildcard character,
453 return it as the basename. */
454 p = name + strlen (name);
455 while (*p != '\\' && *p != ':' && p > name) p--;
457 if (strchr (p, '*') || strchr (p, '?'))
459 if ((len = strlen (p)) < size)
460 memcpy (buf, p, len + 1);
467 dir_handle = FindFirstFile (name, &find_data);
468 if (dir_handle != INVALID_HANDLE_VALUE)
470 if ((len = strlen (find_data.cFileName)) < size)
471 memcpy (buf, find_data.cFileName, len + 1);
474 FindClose (dir_handle);
479 /* Get long name for file, if possible (assumed to be absolute). */
481 win32_get_long_filename (char * name, char * buf, int size)
486 char full[ MAX_PATH ];
493 /* Use local copy for destructive modification. */
494 memcpy (full, name, len+1);
495 unixtodos_filename (full);
497 /* Copy root part verbatim. */
498 len = parse_root (full, &p);
499 memcpy (o, full, len);
506 p = strchr (q, '\\');
508 len = get_long_basename (full, o, size);
526 while (p != NULL && *p);
532 /* Routines that are no-ops on NT but are defined to get Emacs to compile. */
534 #if 0 /* #### We do not need those, do we? -kkm */
536 unrequest_sigio (void)
548 #define REG_ROOT "SOFTWARE\\GNU\\XEmacs"
551 nt_get_resource (char *key, LPDWORD lpdwtype)
554 HKEY hrootkey = NULL;
557 /* Check both the current user and the local machine to see if
558 we have any resources. */
560 if (RegOpenKeyEx (HKEY_CURRENT_USER, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
564 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
565 && (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL
566 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
571 if (lpvalue) xfree (lpvalue);
573 RegCloseKey (hrootkey);
576 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
580 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS &&
581 (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL &&
582 RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
587 if (lpvalue) xfree (lpvalue);
589 RegCloseKey (hrootkey);
598 /* Check for environment variables and use registry if they don't exist */
604 static char * env_vars[] =
619 cache_system_info ();
621 for (i = 0; i < countof (env_vars); i++)
623 if (!getenv (env_vars[i]) &&
624 (lpval = nt_get_resource (env_vars[i], &dwType)) != NULL)
626 if (dwType == REG_EXPAND_SZ)
628 char buf1[500], buf2[500];
630 ExpandEnvironmentStrings ((LPSTR) lpval, buf1, 500);
631 _snprintf (buf2, 499, "%s=%s", env_vars[i], buf1);
632 putenv (strdup (buf2));
634 else if (dwType == REG_SZ)
638 _snprintf (buf, 499, "%s=%s", env_vars[i], lpval);
639 putenv (strdup (buf));
647 /* Another special case: on NT, the PATH variable is actually named
648 "Path" although cmd.exe (perhaps NT itself) arranges for
649 environment variable lookup and setting to be case insensitive.
650 However, Emacs assumes a fully case sensitive environment, so we
651 need to change "Path" to "PATH" to match the expectations of
652 various elisp packages. We do this by the sneaky method of
653 modifying the string in the C runtime environ entry.
655 The same applies to COMSPEC. */
659 for (envp = environ; *envp; envp++)
660 if (_strnicmp (*envp, "PATH=", 5) == 0)
661 memcpy (*envp, "PATH=", 5);
662 else if (_strnicmp (*envp, "COMSPEC=", 8) == 0)
663 memcpy (*envp, "COMSPEC=", 8);
666 /* Remember the initial working directory for getwd, then make the
667 real wd be the location of emacs.exe to avoid conflicts when
668 renaming or deleting directories. (We also don't call chdir when
669 running subprocesses for the same reason.) */
670 if (!GetCurrentDirectory (MAXPATHLEN, startup_dir))
675 char modname[MAX_PATH];
677 if (!GetModuleFileName (NULL, modname, MAX_PATH))
679 if ((p = strrchr (modname, '\\')) == NULL)
683 SetCurrentDirectory (modname);
689 #ifndef HAVE_X_WINDOWS
690 /* X11R6 on NT provides the single parameter version of this command. */
692 #include <sys/timeb.h>
694 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
696 gettimeofday (struct timeval *tv, struct timezone *tz)
701 tv->tv_sec = tb.time;
702 tv->tv_usec = tb.millitm * 1000L;
705 tz->tz_minuteswest = tb.timezone; /* minutes west of Greenwich */
706 tz->tz_dsttime = tb.dstflag; /* type of dst correction */
710 #endif /* HAVE_X_WINDOWS */
712 /* ------------------------------------------------------------------------- */
713 /* IO support and wrapper functions for Win32 API. */
714 /* ------------------------------------------------------------------------- */
716 /* Place a wrapper around the MSVC version of ctime. It returns NULL
717 on network directories, so we handle that case here.
718 (Ulrich Leodolter, 1/11/95). */
720 sys_ctime (const time_t *t)
722 char *str = (char *) ctime (t);
723 return (str ? str : "Sun Jan 01 00:00:00 1970");
726 /* Emulate sleep...we could have done this with a define, but that
727 would necessitate including windows.h in the files that used it.
728 This is much easier. */
730 #ifndef HAVE_X_WINDOWS
732 sys_sleep (int seconds)
734 Sleep (seconds * 1000);
738 /* #### This is an evil dirty hack. We must get rid of it.
739 Word "munging" is not in XEmacs lexicon. - kkm */
741 /* Internal MSVC data and functions for low-level descriptor munging */
742 #if (_MSC_VER == 900)
743 extern char _osfile[];
745 extern int __cdecl _set_osfhnd (int fd, long h);
746 extern int __cdecl _free_osfhnd (int fd);
748 /* parallel array of private info on file handles */
749 filedesc fd_info [ MAXDESC ];
751 typedef struct volume_info_data {
752 struct volume_info_data * next;
754 /* time when info was obtained */
757 /* actual volume info */
766 /* Global referenced by various functions. */
767 static volume_info_data volume_info;
769 /* Vector to indicate which drives are local and fixed (for which cached
770 data never expires). */
771 static BOOL fixed_drives[26];
773 /* Consider cached volume information to be stale if older than 10s,
774 at least for non-local drives. Info for fixed drives is never stale. */
775 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
776 #define VOLINFO_STILL_VALID( root_dir, info ) \
777 ( ( isalpha (root_dir[0]) && \
778 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
779 || GetTickCount () - info->timestamp < 10000 )
781 /* Cache support functions. */
783 /* Simple linked list with linear search is sufficient. */
784 static volume_info_data *volume_cache = NULL;
786 static volume_info_data *
787 lookup_volume_info (char * root_dir)
789 volume_info_data * info;
791 for (info = volume_cache; info; info = info->next)
792 if (stricmp (info->root_dir, root_dir) == 0)
798 add_volume_info (char * root_dir, volume_info_data * info)
800 info->root_dir = xstrdup (root_dir);
801 info->next = volume_cache;
806 /* Wrapper for GetVolumeInformation, which uses caching to avoid
807 performance penalty (~2ms on 486 for local drives, 7.5ms for local
808 cdrom drive, ~5-10ms or more for remote drives on LAN). */
810 GetCachedVolumeInformation (char * root_dir)
812 volume_info_data * info;
813 char default_root[ MAX_PATH ];
815 /* NULL for root_dir means use root from current directory. */
816 if (root_dir == NULL)
818 if (GetCurrentDirectory (MAX_PATH, default_root) == 0)
820 parse_root (default_root, &root_dir);
822 root_dir = default_root;
825 /* Local fixed drives can be cached permanently. Removable drives
826 cannot be cached permanently, since the volume name and serial
827 number (if nothing else) can change. Remote drives should be
828 treated as if they are removable, since there is no sure way to
829 tell whether they are or not. Also, the UNC association of drive
830 letters mapped to remote volumes can be changed at any time (even
831 by other processes) without notice.
833 As a compromise, so we can benefit from caching info for remote
834 volumes, we use a simple expiry mechanism to invalidate cache
835 entries that are more than ten seconds old. */
838 /* No point doing this, because WNetGetConnection is even slower than
839 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
840 GetDriveType is about the only call of this type which does not
841 involve network access, and so is extremely quick). */
843 /* Map drive letter to UNC if remote. */
844 if ( isalpha( root_dir[0] ) && !fixed[ DRIVE_INDEX( root_dir[0] ) ] )
846 char remote_name[ 256 ];
847 char drive[3] = { root_dir[0], ':' };
849 if (WNetGetConnection (drive, remote_name, sizeof (remote_name))
855 info = lookup_volume_info (root_dir);
857 if (info == NULL || ! VOLINFO_STILL_VALID (root_dir, info))
865 /* Info is not cached, or is stale. */
866 if (!GetVolumeInformation (root_dir,
871 type, sizeof (type)))
874 /* Cache the volume information for future use, overwriting existing
878 info = (volume_info_data *) xmalloc (sizeof (volume_info_data));
879 add_volume_info (root_dir, info);
887 info->name = xstrdup (name);
888 info->serialnum = serialnum;
889 info->maxcomp = maxcomp;
891 info->type = xstrdup (type);
892 info->timestamp = GetTickCount ();
898 /* Get information on the volume where name is held; set path pointer to
899 start of pathname in name (past UNC header\volume header if present). */
901 get_volume_info (const char * name, const char ** pPath)
904 char *rootname = NULL; /* default to current volume */
905 volume_info_data * info;
910 /* find the root name of the volume if given */
911 if (isalpha (name[0]) && name[1] == ':')
919 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
926 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
939 info = GetCachedVolumeInformation (rootname);
942 /* Set global referenced by other functions. */
949 /* Determine if volume is FAT format (ie. only supports short 8.3
950 names); also set path pointer to start of pathname in name. */
952 is_fat_volume (const char * name, const char ** pPath)
954 if (get_volume_info (name, pPath))
955 return (volume_info.maxcomp == 12);
959 /* Map filename to a legal 8.3 name if necessary. */
961 map_win32_filename (const char * name, const char ** pPath)
963 static char shortname[MAX_PATH];
964 char * str = shortname;
967 const char * save_name = name;
969 if (is_fat_volume (name, &path)) /* truncate to 8.3 */
971 REGISTER int left = 8; /* maximum number of chars in part */
972 REGISTER int extn = 0; /* extension added? */
973 REGISTER int dots = 2; /* maximum number of dots allowed */
976 *str++ = *name++; /* skip past UNC header */
978 while ((c = *name++))
985 extn = 0; /* reset extension flags */
986 dots = 2; /* max 2 dots */
987 left = 8; /* max length 8 for main part */
991 extn = 0; /* reset extension flags */
992 dots = 2; /* max 2 dots */
993 left = 8; /* max length 8 for main part */
998 /* Convert path components of the form .xxx to _xxx,
999 but leave . and .. as they are. This allows .emacs
1000 to be read as _emacs, for example. */
1004 IS_DIRECTORY_SEP (*name))
1019 extn = 1; /* we've got an extension */
1020 left = 3; /* 3 chars in extension */
1024 /* any embedded dots after the first are converted to _ */
1029 case '#': /* don't lose these, they're important */
1031 str[-1] = c; /* replace last character of part */
1036 *str++ = tolower (c); /* map to lower case (looks nicer) */
1038 dots = 0; /* started a path component */
1047 strcpy (shortname, name);
1048 unixtodos_filename (shortname);
1052 *pPath = shortname + (path - save_name);
1058 /* Emulate the Unix directory procedures opendir, closedir,
1059 and readdir. We can't use the procedures supplied in sysdep.c,
1060 so we provide them here. */
1062 struct direct dir_static; /* simulated directory contents */
1063 static HANDLE dir_find_handle = INVALID_HANDLE_VALUE;
1064 static int dir_is_fat;
1065 static char dir_pathname[MAXPATHLEN+1];
1066 static WIN32_FIND_DATA dir_find_data;
1069 opendir (const char *filename)
1073 /* Opening is done by FindFirstFile. However, a read is inherent to
1074 this operation, so we defer the open until read time. */
1076 if (!(dirp = xnew_and_zero(DIR)))
1078 if (dir_find_handle != INVALID_HANDLE_VALUE)
1085 strncpy (dir_pathname, map_win32_filename (filename, NULL), MAXPATHLEN);
1086 dir_pathname[MAXPATHLEN] = '\0';
1087 dir_is_fat = is_fat_volume (filename, NULL);
1093 closedir (DIR *dirp)
1095 /* If we have a find-handle open, close it. */
1096 if (dir_find_handle != INVALID_HANDLE_VALUE)
1098 FindClose (dir_find_handle);
1099 dir_find_handle = INVALID_HANDLE_VALUE;
1107 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
1108 if (dir_find_handle == INVALID_HANDLE_VALUE)
1110 char filename[MAXNAMLEN + 3];
1113 strcpy (filename, dir_pathname);
1114 ln = strlen (filename) - 1;
1115 if (!IS_DIRECTORY_SEP (filename[ln]))
1116 strcat (filename, "\\");
1117 strcat (filename, "*");
1119 dir_find_handle = FindFirstFile (filename, &dir_find_data);
1121 if (dir_find_handle == INVALID_HANDLE_VALUE)
1126 if (!FindNextFile (dir_find_handle, &dir_find_data))
1130 /* Emacs never uses this value, so don't bother making it match
1131 value returned by stat(). */
1132 dir_static.d_ino = 1;
1134 dir_static.d_reclen = sizeof (struct direct) - MAXNAMLEN + 3 +
1135 dir_static.d_namlen - dir_static.d_namlen % 4;
1137 dir_static.d_namlen = strlen (dir_find_data.cFileName);
1138 strcpy (dir_static.d_name, dir_find_data.cFileName);
1140 _strlwr (dir_static.d_name);
1141 else if (!NILP (Vmswindows_downcase_file_names))
1144 for (p = dir_static.d_name; *p; p++)
1145 if (*p >= 'a' && *p <= 'z')
1148 _strlwr (dir_static.d_name);
1155 /* #### Have to check if all that sad story about '95 is true - kkm */
1157 sys_rename (const char * oldname, const char * newname)
1159 char temp[MAX_PATH];
1162 /* MoveFile on Win95 doesn't correctly change the short file name
1163 alias in a number of circumstances (it is not easy to predict when
1164 just by looking at oldname and newname, unfortunately). In these
1165 cases, renaming through a temporary name avoids the problem.
1167 A second problem on Win95 is that renaming through a temp name when
1168 newname is uppercase fails (the final long name ends up in
1169 lowercase, although the short alias might be uppercase) UNLESS the
1170 long temp name is not 8.3.
1172 So, on Win95 we always rename through a temp name, and we make sure
1173 the temp name has a long extension to ensure correct renaming. */
1175 strcpy (temp, map_win32_filename (oldname, NULL));
1177 if (GetVersion () & 0x80000000)
1181 if (p = strrchr (temp, '\\'))
1185 /* Force temp name to require a manufactured 8.3 alias - this
1186 seems to make the second rename work properly. */
1187 strcpy (p, "_rename_temp.XXXXXX");
1189 if (rename (map_win32_filename (oldname, NULL), temp) < 0)
1193 /* Emulate Unix behavior - newname is deleted if it already exists
1194 (at least if it is a file; don't do this for directories).
1195 However, don't do this if we are just changing the case of the file
1196 name - we will end up deleting the file we are trying to rename! */
1197 newname = map_win32_filename (newname, NULL);
1199 /* TODO: Use GetInformationByHandle (on NT) to ensure newname and temp
1200 do not refer to the same file, eg. through share aliases. */
1201 if (stricmp (newname, temp) != 0
1202 && (attr = GetFileAttributes (newname)) != -1
1203 && (attr & FILE_ATTRIBUTE_DIRECTORY) == 0)
1205 _chmod (newname, 0666);
1209 return rename (temp, newname);
1213 static FILETIME utc_base_ft;
1214 static int init = 0;
1218 static long double utc_base;
1221 convert_time (FILETIME ft)
1227 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
1236 st.wMilliseconds = 0;
1238 SystemTimeToFileTime (&st, &utc_base_ft);
1239 utc_base = (long double) utc_base_ft.dwHighDateTime
1240 * 4096 * 1024 * 1024 + utc_base_ft.dwLowDateTime;
1244 if (CompareFileTime (&ft, &utc_base_ft) < 0)
1247 ret = (long double) ft.dwHighDateTime * 4096 * 1024 * 1024 + ft.dwLowDateTime;
1249 return (time_t) (ret * 1e-7);
1253 static LARGE_INTEGER utc_base_li;
1256 convert_time (FILETIME uft)
1263 TIME_ZONE_INFORMATION tzi;
1271 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
1280 st.wMilliseconds = 0;
1282 SystemTimeToFileTime (&st, &utc_base_ft);
1284 utc_base_li.LowPart = utc_base_ft.dwLowDateTime;
1285 utc_base_li.HighPart = utc_base_ft.dwHighDateTime;
1292 /* On a compiler that supports long integers, do it the easy way */
1293 lft.LowPart = uft.dwLowDateTime;
1294 lft.HighPart = uft.dwHighDateTime;
1295 ret = (time_t) ((lft.QuadPart - utc_base_li.QuadPart) / 10000000);
1299 /* Do it the hard way using mktime. */
1300 FileTimeToLocalFileTime(&uft, &ft);
1301 FileTimeToSystemTime (&ft, &st);
1302 tzid = GetTimeZoneInformation (&tzi);
1303 t.tm_year = st.wYear - 1900;
1304 t.tm_mon = st.wMonth - 1;
1305 t.tm_mday = st.wDay;
1306 t.tm_hour = st.wHour;
1307 t.tm_min = st.wMinute;
1308 t.tm_sec = st.wSecond;
1309 t.tm_isdst = (tzid == TIME_ZONE_ID_DAYLIGHT);
1310 /* st.wMilliseconds not applicable */
1324 /* in case we ever have need of this */
1326 convert_from_time_t (time_t time, FILETIME * pft)
1332 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
1341 st.wMilliseconds = 0;
1343 SystemTimeToFileTime (&st, &utc_base_ft);
1344 utc_base = (long double) utc_base_ft.dwHighDateTime
1345 * 4096 * 1024 * 1024 + utc_base_ft.dwLowDateTime;
1349 /* time in 100ns units since 1-Jan-1601 */
1350 tmp = (long double) time * 1e7 + utc_base;
1351 pft->dwHighDateTime = (DWORD) (tmp / (4096.0 * 1024 * 1024));
1352 pft->dwLowDateTime = (DWORD) (tmp - pft->dwHighDateTime);
1357 /* No reason to keep this; faking inode values either by hashing or even
1358 using the file index from GetInformationByHandle, is not perfect and
1359 so by default Emacs doesn't use the inode values on Windows.
1360 Instead, we now determine file-truename correctly (except for
1361 possible drive aliasing etc). */
1363 /* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
1365 hashval (const unsigned char * str)
1370 h = (h << 4) + *str++;
1376 /* Return the hash value of the canonical pathname, excluding the
1377 drive/UNC header, to get a hopefully unique inode number. */
1379 generate_inode_val (const char * name)
1381 char fullname[ MAX_PATH ];
1385 /* Get the truly canonical filename, if it exists. (Note: this
1386 doesn't resolve aliasing due to subst commands, or recognize hard
1388 if (!win32_get_long_filename ((char *)name, fullname, MAX_PATH))
1391 parse_root (fullname, &p);
1392 /* Normal Win32 filesystems are still case insensitive. */
1399 /* stat has been fixed since MSVC 5.0.
1400 Oh, and do not encapsulater stat for non-MS compilers, too */
1401 /* #### popineau@ese-metz.fr says they still might be broken.
1402 Oh well... Let's add that `1 ||' condition.... --kkm */
1403 #if 1 || defined(_MSC_VER) && _MSC_VER < 1100
1405 /* Since stat is encapsulated on Windows NT, we need to encapsulate
1406 the equally broken fstat as well. */
1408 fstat (int handle, struct stat *buffer)
1411 BY_HANDLE_FILE_INFORMATION lpFileInfo;
1412 /* Initialize values */
1413 buffer->st_mode = 0;
1414 buffer->st_size = 0;
1416 buffer->st_rdev = 0;
1417 buffer->st_atime = 0;
1418 buffer->st_ctime = 0;
1419 buffer->st_mtime = 0;
1420 buffer->st_nlink = 0;
1421 ret = GetFileInformationByHandle((HANDLE) _get_osfhandle(handle), &lpFileInfo);
1428 buffer->st_mtime = convert_time (lpFileInfo.ftLastWriteTime);
1429 buffer->st_atime = convert_time (lpFileInfo.ftLastAccessTime);
1430 if (buffer->st_atime == 0) buffer->st_atime = buffer->st_mtime;
1431 buffer->st_ctime = convert_time (lpFileInfo.ftCreationTime);
1432 if (buffer->st_ctime == 0) buffer->st_ctime = buffer->st_mtime;
1433 buffer->st_size = lpFileInfo.nFileSizeLow;
1434 buffer->st_nlink = (short) lpFileInfo.nNumberOfLinks;
1439 /* MSVC stat function can't cope with UNC names and has other bugs, so
1440 replace it with our own. This also allows us to calculate consistent
1441 inode values without hacks in the main Emacs code. */
1443 stat (const char * path, struct stat * buf)
1446 WIN32_FIND_DATA wfd;
1451 int rootdir = FALSE;
1453 if (path == NULL || buf == NULL)
1459 name = (char *) map_win32_filename (path, &path);
1460 /* must be valid filename, no wild cards */
1461 if (strchr (name, '*') || strchr (name, '?'))
1467 /* Remove trailing directory separator, unless name is the root
1468 directory of a drive or UNC volume in which case ensure there
1469 is a trailing separator. */
1470 len = strlen (name);
1471 rootdir = (path >= name + len - 1
1472 && (IS_DIRECTORY_SEP (*path) || *path == 0));
1473 name = strcpy ((char *)alloca (len + 2), name);
1477 if (!IS_DIRECTORY_SEP (name[len-1]))
1478 strcat (name, "\\");
1479 if (GetDriveType (name) < 2)
1484 memset (&wfd, 0, sizeof (wfd));
1485 wfd.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
1486 wfd.ftCreationTime = utc_base_ft;
1487 wfd.ftLastAccessTime = utc_base_ft;
1488 wfd.ftLastWriteTime = utc_base_ft;
1489 strcpy (wfd.cFileName, name);
1493 if (IS_DIRECTORY_SEP (name[len-1]))
1496 /* (This is hacky, but helps when doing file completions on
1497 network drives.) Optimize by using information available from
1498 active readdir if possible. */
1499 if (dir_find_handle != INVALID_HANDLE_VALUE &&
1500 (len = strlen (dir_pathname)),
1501 strnicmp (name, dir_pathname, len) == 0 &&
1502 IS_DIRECTORY_SEP (name[len]) &&
1503 stricmp (name + len + 1, dir_static.d_name) == 0)
1505 /* This was the last entry returned by readdir. */
1506 wfd = dir_find_data;
1510 fh = FindFirstFile (name, &wfd);
1511 if (fh == INVALID_HANDLE_VALUE)
1520 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1522 buf->st_mode = _S_IFDIR;
1523 buf->st_nlink = 2; /* doesn't really matter */
1524 fake_inode = 0; /* this doesn't either I think */
1526 else if (!NILP (Vmswindows_get_true_file_attributes))
1528 /* This is more accurate in terms of getting the correct number
1529 of links, but is quite slow (it is noticeable when Emacs is
1530 making a list of file name completions). */
1531 BY_HANDLE_FILE_INFORMATION info;
1533 /* No access rights required to get info. */
1534 fh = CreateFile (name, 0, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
1535 OPEN_EXISTING, 0, NULL);
1537 if (GetFileInformationByHandle (fh, &info))
1539 switch (GetFileType (fh))
1541 case FILE_TYPE_DISK:
1542 buf->st_mode = _S_IFREG;
1544 case FILE_TYPE_PIPE:
1545 buf->st_mode = _S_IFIFO;
1547 case FILE_TYPE_CHAR:
1548 case FILE_TYPE_UNKNOWN:
1550 buf->st_mode = _S_IFCHR;
1552 buf->st_nlink = (short) info.nNumberOfLinks;
1553 /* Might as well use file index to fake inode values, but this
1554 is not guaranteed to be unique unless we keep a handle open
1555 all the time (even then there are situations where it is
1556 not unique). Reputedly, there are at most 48 bits of info
1557 (on NTFS, presumably less on FAT). */
1558 fake_inode = info.nFileIndexLow ^ info.nFileIndexHigh;
1569 /* Don't bother to make this information more accurate. */
1570 buf->st_mode = _S_IFREG;
1576 /* Not sure if there is any point in this. */
1577 if (!NILP (Vwin32_generate_fake_inodes))
1578 fake_inode = generate_inode_val (name);
1579 else if (fake_inode == 0)
1581 /* For want of something better, try to make everything unique. */
1582 static DWORD gen_num = 0;
1583 fake_inode = ++gen_num;
1587 /* #### MSVC defines _ino_t to be short; other libc's might not. */
1588 buf->st_ino = (unsigned short) (fake_inode ^ (fake_inode >> 16));
1590 /* consider files to belong to current user */
1591 buf->st_uid = buf->st_gid = nt_fake_unix_uid;
1593 /* volume_info is set indirectly by map_win32_filename */
1594 buf->st_dev = volume_info.serialnum;
1595 buf->st_rdev = volume_info.serialnum;
1597 buf->st_size = wfd.nFileSizeLow;
1599 /* Convert timestamps to Unix format. */
1600 buf->st_mtime = convert_time (wfd.ftLastWriteTime);
1601 buf->st_atime = convert_time (wfd.ftLastAccessTime);
1602 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
1603 buf->st_ctime = convert_time (wfd.ftCreationTime);
1604 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
1606 /* determine rwx permissions */
1607 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
1608 permission = _S_IREAD;
1610 permission = _S_IREAD | _S_IWRITE;
1612 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1613 permission |= _S_IEXEC;
1616 char * p = strrchr (name, '.');
1618 (stricmp (p, ".exe") == 0 ||
1619 stricmp (p, ".com") == 0 ||
1620 stricmp (p, ".bat") == 0 ||
1621 stricmp (p, ".cmd") == 0))
1622 permission |= _S_IEXEC;
1625 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
1629 #endif /* defined(_MSC_VER) && _MSC_VER < 1100 */
1631 /* From callproc.c */
1632 extern Lisp_Object Vbinary_process_input;
1633 extern Lisp_Object Vbinary_process_output;
1635 /* Unix pipe() has only one arg */
1637 sys_pipe (int * phandles)
1642 /* make pipe handles non-inheritable; when we spawn a child, we
1643 replace the relevant handle with an inheritable one. Also put
1644 pipes into binary mode; we will do text mode translation ourselves
1646 rc = _pipe (phandles, 0, _O_NOINHERIT | _O_BINARY);
1650 flags = FILE_PIPE | FILE_READ;
1651 if (!NILP (Vbinary_process_output))
1652 flags |= FILE_BINARY;
1653 fd_info[phandles[0]].flags = flags;
1655 flags = FILE_PIPE | FILE_WRITE;
1656 if (!NILP (Vbinary_process_input))
1657 flags |= FILE_BINARY;
1658 fd_info[phandles[1]].flags = flags;
1665 term_ntproc (int unused)
1672 /* Initial preparation for subprocess support: replace our standard
1673 handles with non-inheritable versions. */
1676 HANDLE stdin_save = INVALID_HANDLE_VALUE;
1677 HANDLE stdout_save = INVALID_HANDLE_VALUE;
1678 HANDLE stderr_save = INVALID_HANDLE_VALUE;
1680 parent = GetCurrentProcess ();
1682 /* ignore errors when duplicating and closing; typically the
1683 handles will be invalid when running as a gui program. */
1684 DuplicateHandle (parent,
1685 GetStdHandle (STD_INPUT_HANDLE),
1690 DUPLICATE_SAME_ACCESS);
1692 DuplicateHandle (parent,
1693 GetStdHandle (STD_OUTPUT_HANDLE),
1698 DUPLICATE_SAME_ACCESS);
1700 DuplicateHandle (parent,
1701 GetStdHandle (STD_ERROR_HANDLE),
1706 DUPLICATE_SAME_ACCESS);
1712 if (stdin_save != INVALID_HANDLE_VALUE)
1713 _open_osfhandle ((long) stdin_save, O_TEXT);
1715 _open ("nul", O_TEXT | O_NOINHERIT | O_RDONLY);
1718 if (stdout_save != INVALID_HANDLE_VALUE)
1719 _open_osfhandle ((long) stdout_save, O_TEXT);
1721 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
1724 if (stderr_save != INVALID_HANDLE_VALUE)
1725 _open_osfhandle ((long) stderr_save, O_TEXT);
1727 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
1731 /* unfortunately, atexit depends on implementation of malloc */
1732 /* atexit (term_ntproc); */
1733 signal (SIGABRT, term_ntproc);
1735 /* determine which drives are fixed, for GetCachedVolumeInformation */
1737 /* GetDriveType must have trailing backslash. */
1738 char drive[] = "A:\\";
1740 /* Loop over all possible drive letters */
1741 while ( *drive <= 'Z' )
1743 /* Record if this drive letter refers to a fixed drive. */
1744 fixed_drives[ DRIVE_INDEX (*drive) ] =
1745 (GetDriveType (drive) == DRIVE_FIXED);
1753 tty_semi_canonicalize_console_connection (Lisp_Object connection,
1754 Error_behavior errb)
1760 tty_canonicalize_console_connection (Lisp_Object connection,
1761 Error_behavior errb)
1767 tty_semi_canonicalize_device_connection (Lisp_Object connection,
1768 Error_behavior errb)
1774 tty_canonicalize_device_connection (Lisp_Object connection,
1775 Error_behavior errb)
1781 /*--------------------------------------------------------------------*/
1782 /* Signal support */
1783 /*--------------------------------------------------------------------*/
1785 /* We need MS-defined signal and raise here */
1789 #define sigmask(nsig) (1U << nsig)
1791 /* We can support as many signals as fit into word */
1794 /* Signal handlers. Initial value = 0 = SIG_DFL */
1795 static void (__cdecl *signal_handlers[SIG_MAX])(int) = {0};
1797 /* Signal block mask: bit set to 1 means blocked */
1798 unsigned signal_block_mask = 0;
1800 /* Signal pending mask: bit set to 1 means sig is pending */
1801 unsigned signal_pending_mask = 0;
1803 msw_sighandler msw_sigset (int nsig, msw_sighandler handler)
1805 /* We delegate some signals to the system function */
1806 if (nsig == SIGFPE || nsig == SIGABRT || nsig == SIGINT)
1807 return signal (nsig, handler);
1809 if (nsig < 0 || nsig > SIG_MAX)
1815 /* Store handler ptr */
1817 msw_sighandler old_handler = signal_handlers[nsig];
1818 signal_handlers[nsig] = handler;
1823 int msw_sighold (int nsig)
1825 if (nsig < 0 || nsig > SIG_MAX)
1826 return errno = EINVAL;
1828 signal_block_mask |= sigmask(nsig);
1832 int msw_sigrelse (int nsig)
1834 if (nsig < 0 || nsig > SIG_MAX)
1835 return errno = EINVAL;
1837 signal_block_mask &= ~sigmask(nsig);
1839 if (signal_pending_mask & sigmask(nsig))
1845 int msw_sigpause (int nsig)
1847 /* This is currently not called, because the only
1848 call to sigpause inside XEmacs is with SIGCHLD
1849 parameter. Just in case, we put an assert here,
1850 so anyone who will add a call to sigpause will
1851 be surprised (or surprise someone else...) */
1856 int msw_raise (int nsig)
1858 /* We delegate some raises to the system routine */
1859 if (nsig == SIGFPE || nsig == SIGABRT || nsig == SIGINT)
1860 return raise (nsig);
1862 if (nsig < 0 || nsig > SIG_MAX)
1863 return errno = EINVAL;
1865 /* If the signal is blocked, remember to issue later */
1866 if (signal_block_mask & sigmask(nsig))
1868 signal_pending_mask |= sigmask(nsig);
1872 if (signal_handlers[nsig] == SIG_IGN)
1875 if (signal_handlers[nsig] != SIG_DFL)
1877 (*signal_handlers[nsig])(nsig);
1881 /* Default signal actions */
1882 if (nsig == SIGALRM || nsig == SIGPROF)
1885 /* Other signals are ignored by default */
1889 /*--------------------------------------------------------------------*/
1891 /*--------------------------------------------------------------------*/
1893 /* We emulate two timers, one for SIGALRM, another for SIGPROF.
1895 itimerproc() function has an implementation limitation: it does
1896 not allow to set *both* interval and period. If an attempt is
1897 made to set both, and then they are unequal, the function
1900 Minimum timer resolution on Win32 systems varies, and is greater
1901 than or equal than 1 ms. The resolution is always wrapped not to
1902 attempt to get below the system defined limit.
1905 /* Timer precision, denominator of one fraction: for 100 ms
1906 interval, request 10 ms precision
1908 const int timer_prec = 10;
1910 /* Last itimervals, as set by calls to setitimer */
1911 static struct itimerval it_alarm;
1912 static struct itimerval it_prof;
1914 /* Timer IDs as returned by MM */
1915 MMRESULT tid_alarm = 0;
1916 MMRESULT tid_prof = 0;
1918 static void CALLBACK timer_proc (UINT uID, UINT uMsg, DWORD dwUser,
1919 DWORD dw1, DWORD dw2)
1921 /* Just raise a signal indicated by dwUser parameter */
1925 /* Divide time in ms specified by IT by DENOM. Return 1 ms
1926 if division results in zero */
1927 static UINT period (const struct itimerval* it, UINT denom)
1929 static TIMECAPS time_caps;
1932 const struct timeval* tv =
1933 (it->it_value.tv_sec == 0 && it->it_value.tv_usec == 0)
1934 ? &it->it_interval : &it->it_value;
1936 /* Zero means stop timer */
1937 if (tv->tv_sec == 0 && tv->tv_usec == 0)
1940 /* Convert to ms and divide by denom */
1941 res = (tv->tv_sec * 1000 + (tv->tv_usec + 500) / 1000) / denom;
1943 /* Converge to minimum timer resolution */
1944 if (time_caps.wPeriodMin == 0)
1945 timeGetDevCaps (&time_caps, sizeof(time_caps));
1947 if (res < time_caps.wPeriodMin)
1948 res = time_caps.wPeriodMin;
1953 static int setitimer_helper (const struct itimerval* itnew,
1954 struct itimerval* itold, struct itimerval* itcurrent,
1955 MMRESULT* tid, DWORD sigkind)
1957 UINT delay, resolution, event_type;
1959 /* First stop the old timer */
1962 timeKillEvent (*tid);
1963 timeEndPeriod (period (itcurrent, timer_prec));
1967 /* Return old itimerval if requested */
1969 *itold = *itcurrent;
1971 *itcurrent = *itnew;
1973 /* Determine if to start new timer */
1974 delay = period (itnew, 1);
1977 resolution = period (itnew, timer_prec);
1978 event_type = (itnew->it_value.tv_sec == 0 && itnew->it_value.tv_usec == 0)
1979 ? TIME_ONESHOT : TIME_PERIODIC;
1980 timeBeginPeriod (resolution);
1981 *tid = timeSetEvent (delay, resolution, timer_proc, sigkind, event_type);
1984 return !delay || *tid;
1987 int setitimer (int kind, const struct itimerval* itnew,
1988 struct itimerval* itold)
1990 /* In this version, both interval and value are allowed
1991 only if they are equal. */
1992 assert ((itnew->it_value.tv_sec == 0 && itnew->it_value.tv_usec == 0)
1993 || (itnew->it_interval.tv_sec == 0 && itnew->it_interval.tv_usec == 0)
1994 || (itnew->it_value.tv_sec == itnew->it_interval.tv_sec &&
1995 itnew->it_value.tv_usec == itnew->it_interval.tv_usec));
1997 if (kind == ITIMER_REAL)
1998 return setitimer_helper (itnew, itold, &it_alarm, &tid_alarm, SIGALRM);
1999 else if (kind == ITIMER_PROF)
2000 return setitimer_helper (itnew, itold, &it_prof, &tid_prof, SIGPROF);
2002 return errno = EINVAL;
2006 open_input_file (file_data *p_file, const char *filename)
2009 HANDLE file_mapping;
2011 DWORD size, upper_size;
2013 file = CreateFile (filename, GENERIC_READ, FILE_SHARE_READ, NULL,
2014 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
2015 if (file == INVALID_HANDLE_VALUE)
2018 size = GetFileSize (file, &upper_size);
2019 file_mapping = CreateFileMapping (file, NULL, PAGE_READONLY,
2024 file_base = MapViewOfFile (file_mapping, FILE_MAP_READ, 0, 0, size);
2028 p_file->name = (char *)filename;
2029 p_file->size = size;
2030 p_file->file = file;
2031 p_file->file_mapping = file_mapping;
2032 p_file->file_base = (char *)file_base;
2037 /* Close the system structures associated with the given file. */
2039 close_file_data (file_data *p_file)
2041 UnmapViewOfFile (p_file->file_base);
2042 CloseHandle (p_file->file_mapping);
2043 CloseHandle (p_file->file);
2049 DEFVAR_INT ("nt-fake-unix-uid", &nt_fake_unix_uid /*
2050 *Set uid returned by `user-uid' and `user-real-uid'.
2051 Under NT and 9x, there is no uids, and even no almighty user called root.
2052 By setting this variable, you can have any uid of choice. Default is 0.
2053 Changes to this variable take effect immediately.
2055 nt_fake_unix_uid = 0;