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, 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 (fp, path_sep)
309 /* Always lower-case drive letters a-z, even if the filesystem
310 preserves case in filenames.
311 This is so filenames can be compared by string comparison
312 functions that are case-sensitive. Even case-preserving filesystems
313 do not distinguish case in drive letters. */
314 if (fp[1] == ':' && *fp >= 'A' && *fp <= 'Z')
320 if (NILP (Vmswindows_downcase_file_names))
324 if (*fp == '/' || *fp == '\\')
331 sep = path_sep; /* convert to this path separator */
332 elem = fp; /* start of current path element */
335 if (*fp >= 'a' && *fp <= 'z')
336 elem = 0; /* don't convert this element */
338 if (*fp == 0 || *fp == ':')
340 sep = *fp; /* restore current separator (or 0) */
341 *fp = '/'; /* after conversion of this element */
344 if (*fp == '/' || *fp == '\\')
346 if (elem && elem != fp)
348 *fp = 0; /* temporary end of string */
349 _strlwr (elem); /* while we convert to lower case */
351 *fp = sep; /* convert (or restore) path separator */
352 elem = fp + 1; /* next element starts after separator */
358 /* Destructively turn backslashes into slashes. */
360 dostounix_filename (p)
363 normalize_filename (p, '/');
366 /* Destructively turn slashes into backslashes. */
368 unixtodos_filename (p)
371 normalize_filename (p, '\\');
374 /* Remove all CR's that are followed by a LF.
375 (From msdos.c...probably should figure out a way to share it,
376 although this code isn't going to ever change.) */
378 crlf_to_lf (n, buf, lf_count)
380 REGISTER unsigned char *buf;
381 REGISTER unsigned *lf_count;
383 unsigned char *np = buf;
384 unsigned char *startp = buf;
385 unsigned char *endp = buf + n;
389 while (buf < endp - 1)
395 if (*(++buf) != 0x0a)
410 /* Parse the root part of file name, if present. Return length and
411 optionally store pointer to char after root. */
413 parse_root (char * name, char ** pPath)
420 /* find the root name of the volume if given */
421 if (isalpha (name[0]) && name[1] == ':')
423 /* skip past drive specifier */
425 if (IS_DIRECTORY_SEP (name[0]))
428 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
434 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
439 if (IS_DIRECTORY_SEP (name[0]))
449 /* Get long base name for name; name is assumed to be absolute. */
451 get_long_basename (char * name, char * buf, int size)
453 WIN32_FIND_DATA find_data;
459 /* If the last component of NAME has a wildcard character,
460 return it as the basename. */
461 p = name + strlen (name);
462 while (*p != '\\' && *p != ':' && p > name) p--;
464 if (strchr (p, '*') || strchr (p, '?'))
466 if ((len = strlen (p)) < size)
467 memcpy (buf, p, len + 1);
474 dir_handle = FindFirstFile (name, &find_data);
475 if (dir_handle != INVALID_HANDLE_VALUE)
477 if ((len = strlen (find_data.cFileName)) < size)
478 memcpy (buf, find_data.cFileName, len + 1);
481 FindClose (dir_handle);
486 /* Get long name for file, if possible (assumed to be absolute). */
488 win32_get_long_filename (char * name, char * buf, int size)
493 char full[ MAX_PATH ];
500 /* Use local copy for destructive modification. */
501 memcpy (full, name, len+1);
502 unixtodos_filename (full);
504 /* Copy root part verbatim. */
505 len = parse_root (full, &p);
506 memcpy (o, full, len);
513 p = strchr (q, '\\');
515 len = get_long_basename (full, o, size);
533 while (p != NULL && *p);
539 /* Routines that are no-ops on NT but are defined to get Emacs to compile. */
541 #if 0 /* #### We do not need those, do we? -kkm */
543 unrequest_sigio (void)
555 #define REG_ROOT "SOFTWARE\\GNU\\XEmacs"
558 nt_get_resource (key, lpdwtype)
563 HKEY hrootkey = NULL;
566 /* Check both the current user and the local machine to see if
567 we have any resources. */
569 if (RegOpenKeyEx (HKEY_CURRENT_USER, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
573 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
574 && (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL
575 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
580 if (lpvalue) xfree (lpvalue);
582 RegCloseKey (hrootkey);
585 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
589 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS &&
590 (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL &&
591 RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
596 if (lpvalue) xfree (lpvalue);
598 RegCloseKey (hrootkey);
607 /* Check for environment variables and use registry if they don't exist */
613 static char * env_vars[] =
628 cache_system_info ();
630 for (i = 0; i < countof (env_vars); i++)
632 if (!getenv (env_vars[i]) &&
633 (lpval = nt_get_resource (env_vars[i], &dwType)) != NULL)
635 if (dwType == REG_EXPAND_SZ)
637 char buf1[500], buf2[500];
639 ExpandEnvironmentStrings ((LPSTR) lpval, buf1, 500);
640 _snprintf (buf2, 499, "%s=%s", env_vars[i], buf1);
641 putenv (strdup (buf2));
643 else if (dwType == REG_SZ)
647 _snprintf (buf, 499, "%s=%s", env_vars[i], lpval);
648 putenv (strdup (buf));
656 /* Another special case: on NT, the PATH variable is actually named
657 "Path" although cmd.exe (perhaps NT itself) arranges for
658 environment variable lookup and setting to be case insensitive.
659 However, Emacs assumes a fully case sensitive environment, so we
660 need to change "Path" to "PATH" to match the expectations of
661 various elisp packages. We do this by the sneaky method of
662 modifying the string in the C runtime environ entry.
664 The same applies to COMSPEC. */
668 for (envp = environ; *envp; envp++)
669 if (_strnicmp (*envp, "PATH=", 5) == 0)
670 memcpy (*envp, "PATH=", 5);
671 else if (_strnicmp (*envp, "COMSPEC=", 8) == 0)
672 memcpy (*envp, "COMSPEC=", 8);
675 /* Remember the initial working directory for getwd, then make the
676 real wd be the location of emacs.exe to avoid conflicts when
677 renaming or deleting directories. (We also don't call chdir when
678 running subprocesses for the same reason.) */
679 if (!GetCurrentDirectory (MAXPATHLEN, startup_dir))
684 char modname[MAX_PATH];
686 if (!GetModuleFileName (NULL, modname, MAX_PATH))
688 if ((p = strrchr (modname, '\\')) == NULL)
692 SetCurrentDirectory (modname);
698 #ifndef HAVE_X_WINDOWS
699 /* X11R6 on NT provides the single parameter version of this command. */
701 #include <sys/timeb.h>
703 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
705 gettimeofday (struct timeval *tv, struct timezone *tz)
710 tv->tv_sec = tb.time;
711 tv->tv_usec = tb.millitm * 1000L;
714 tz->tz_minuteswest = tb.timezone; /* minutes west of Greenwich */
715 tz->tz_dsttime = tb.dstflag; /* type of dst correction */
719 #endif /* HAVE_X_WINDOWS */
721 /* ------------------------------------------------------------------------- */
722 /* IO support and wrapper functions for Win32 API. */
723 /* ------------------------------------------------------------------------- */
725 /* Place a wrapper around the MSVC version of ctime. It returns NULL
726 on network directories, so we handle that case here.
727 (Ulrich Leodolter, 1/11/95). */
729 sys_ctime (const time_t *t)
731 char *str = (char *) ctime (t);
732 return (str ? str : "Sun Jan 01 00:00:00 1970");
735 /* Emulate sleep...we could have done this with a define, but that
736 would necessitate including windows.h in the files that used it.
737 This is much easier. */
739 #ifndef HAVE_X_WINDOWS
741 sys_sleep (int seconds)
743 Sleep (seconds * 1000);
747 /* #### This is an evil dirty hack. We must get rid of it.
748 Word "munging" is not in XEmacs lexicon. - kkm */
750 /* Internal MSVC data and functions for low-level descriptor munging */
751 #if (_MSC_VER == 900)
752 extern char _osfile[];
754 extern int __cdecl _set_osfhnd (int fd, long h);
755 extern int __cdecl _free_osfhnd (int fd);
757 /* parallel array of private info on file handles */
758 filedesc fd_info [ MAXDESC ];
760 typedef struct volume_info_data {
761 struct volume_info_data * next;
763 /* time when info was obtained */
766 /* actual volume info */
775 /* Global referenced by various functions. */
776 static volume_info_data volume_info;
778 /* Vector to indicate which drives are local and fixed (for which cached
779 data never expires). */
780 static BOOL fixed_drives[26];
782 /* Consider cached volume information to be stale if older than 10s,
783 at least for non-local drives. Info for fixed drives is never stale. */
784 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
785 #define VOLINFO_STILL_VALID( root_dir, info ) \
786 ( ( isalpha (root_dir[0]) && \
787 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
788 || GetTickCount () - info->timestamp < 10000 )
790 /* Cache support functions. */
792 /* Simple linked list with linear search is sufficient. */
793 static volume_info_data *volume_cache = NULL;
795 static volume_info_data *
796 lookup_volume_info (char * root_dir)
798 volume_info_data * info;
800 for (info = volume_cache; info; info = info->next)
801 if (stricmp (info->root_dir, root_dir) == 0)
807 add_volume_info (char * root_dir, volume_info_data * info)
809 info->root_dir = xstrdup (root_dir);
810 info->next = volume_cache;
815 /* Wrapper for GetVolumeInformation, which uses caching to avoid
816 performance penalty (~2ms on 486 for local drives, 7.5ms for local
817 cdrom drive, ~5-10ms or more for remote drives on LAN). */
819 GetCachedVolumeInformation (char * root_dir)
821 volume_info_data * info;
822 char default_root[ MAX_PATH ];
824 /* NULL for root_dir means use root from current directory. */
825 if (root_dir == NULL)
827 if (GetCurrentDirectory (MAX_PATH, default_root) == 0)
829 parse_root (default_root, &root_dir);
831 root_dir = default_root;
834 /* Local fixed drives can be cached permanently. Removable drives
835 cannot be cached permanently, since the volume name and serial
836 number (if nothing else) can change. Remote drives should be
837 treated as if they are removable, since there is no sure way to
838 tell whether they are or not. Also, the UNC association of drive
839 letters mapped to remote volumes can be changed at any time (even
840 by other processes) without notice.
842 As a compromise, so we can benefit from caching info for remote
843 volumes, we use a simple expiry mechanism to invalidate cache
844 entries that are more than ten seconds old. */
847 /* No point doing this, because WNetGetConnection is even slower than
848 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
849 GetDriveType is about the only call of this type which does not
850 involve network access, and so is extremely quick). */
852 /* Map drive letter to UNC if remote. */
853 if ( isalpha( root_dir[0] ) && !fixed[ DRIVE_INDEX( root_dir[0] ) ] )
855 char remote_name[ 256 ];
856 char drive[3] = { root_dir[0], ':' };
858 if (WNetGetConnection (drive, remote_name, sizeof (remote_name))
864 info = lookup_volume_info (root_dir);
866 if (info == NULL || ! VOLINFO_STILL_VALID (root_dir, info))
874 /* Info is not cached, or is stale. */
875 if (!GetVolumeInformation (root_dir,
880 type, sizeof (type)))
883 /* Cache the volume information for future use, overwriting existing
887 info = (volume_info_data *) xmalloc (sizeof (volume_info_data));
888 add_volume_info (root_dir, info);
896 info->name = xstrdup (name);
897 info->serialnum = serialnum;
898 info->maxcomp = maxcomp;
900 info->type = xstrdup (type);
901 info->timestamp = GetTickCount ();
907 /* Get information on the volume where name is held; set path pointer to
908 start of pathname in name (past UNC header\volume header if present). */
910 get_volume_info (const char * name, const char ** pPath)
913 char *rootname = NULL; /* default to current volume */
914 volume_info_data * info;
919 /* find the root name of the volume if given */
920 if (isalpha (name[0]) && name[1] == ':')
928 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
935 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
948 info = GetCachedVolumeInformation (rootname);
951 /* Set global referenced by other functions. */
958 /* Determine if volume is FAT format (ie. only supports short 8.3
959 names); also set path pointer to start of pathname in name. */
961 is_fat_volume (const char * name, const char ** pPath)
963 if (get_volume_info (name, pPath))
964 return (volume_info.maxcomp == 12);
968 /* Map filename to a legal 8.3 name if necessary. */
970 map_win32_filename (const char * name, const char ** pPath)
972 static char shortname[MAX_PATH];
973 char * str = shortname;
976 const char * save_name = name;
978 if (is_fat_volume (name, &path)) /* truncate to 8.3 */
980 REGISTER int left = 8; /* maximum number of chars in part */
981 REGISTER int extn = 0; /* extension added? */
982 REGISTER int dots = 2; /* maximum number of dots allowed */
985 *str++ = *name++; /* skip past UNC header */
987 while ((c = *name++))
994 extn = 0; /* reset extension flags */
995 dots = 2; /* max 2 dots */
996 left = 8; /* max length 8 for main part */
1000 extn = 0; /* reset extension flags */
1001 dots = 2; /* max 2 dots */
1002 left = 8; /* max length 8 for main part */
1007 /* Convert path components of the form .xxx to _xxx,
1008 but leave . and .. as they are. This allows .emacs
1009 to be read as _emacs, for example. */
1013 IS_DIRECTORY_SEP (*name))
1028 extn = 1; /* we've got an extension */
1029 left = 3; /* 3 chars in extension */
1033 /* any embedded dots after the first are converted to _ */
1038 case '#': /* don't lose these, they're important */
1040 str[-1] = c; /* replace last character of part */
1045 *str++ = tolower (c); /* map to lower case (looks nicer) */
1047 dots = 0; /* started a path component */
1056 strcpy (shortname, name);
1057 unixtodos_filename (shortname);
1061 *pPath = shortname + (path - save_name);
1067 /* Emulate the Unix directory procedures opendir, closedir,
1068 and readdir. We can't use the procedures supplied in sysdep.c,
1069 so we provide them here. */
1071 struct direct dir_static; /* simulated directory contents */
1072 static HANDLE dir_find_handle = INVALID_HANDLE_VALUE;
1073 static int dir_is_fat;
1074 static char dir_pathname[MAXPATHLEN+1];
1075 static WIN32_FIND_DATA dir_find_data;
1078 opendir (const char *filename)
1082 /* Opening is done by FindFirstFile. However, a read is inherent to
1083 this operation, so we defer the open until read time. */
1085 if (!(dirp = xnew_and_zero(DIR)))
1087 if (dir_find_handle != INVALID_HANDLE_VALUE)
1094 strncpy (dir_pathname, map_win32_filename (filename, NULL), MAXPATHLEN);
1095 dir_pathname[MAXPATHLEN] = '\0';
1096 dir_is_fat = is_fat_volume (filename, NULL);
1102 closedir (DIR *dirp)
1104 /* If we have a find-handle open, close it. */
1105 if (dir_find_handle != INVALID_HANDLE_VALUE)
1107 FindClose (dir_find_handle);
1108 dir_find_handle = INVALID_HANDLE_VALUE;
1116 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
1117 if (dir_find_handle == INVALID_HANDLE_VALUE)
1119 char filename[MAXNAMLEN + 3];
1122 strcpy (filename, dir_pathname);
1123 ln = strlen (filename) - 1;
1124 if (!IS_DIRECTORY_SEP (filename[ln]))
1125 strcat (filename, "\\");
1126 strcat (filename, "*");
1128 dir_find_handle = FindFirstFile (filename, &dir_find_data);
1130 if (dir_find_handle == INVALID_HANDLE_VALUE)
1135 if (!FindNextFile (dir_find_handle, &dir_find_data))
1139 /* Emacs never uses this value, so don't bother making it match
1140 value returned by stat(). */
1141 dir_static.d_ino = 1;
1143 dir_static.d_reclen = sizeof (struct direct) - MAXNAMLEN + 3 +
1144 dir_static.d_namlen - dir_static.d_namlen % 4;
1146 dir_static.d_namlen = strlen (dir_find_data.cFileName);
1147 strcpy (dir_static.d_name, dir_find_data.cFileName);
1149 _strlwr (dir_static.d_name);
1150 else if (!NILP (Vmswindows_downcase_file_names))
1153 for (p = dir_static.d_name; *p; p++)
1154 if (*p >= 'a' && *p <= 'z')
1157 _strlwr (dir_static.d_name);
1164 /* #### Have to check if all that sad story about '95 is true - kkm */
1166 sys_rename (const char * oldname, const char * newname)
1168 char temp[MAX_PATH];
1171 /* MoveFile on Win95 doesn't correctly change the short file name
1172 alias in a number of circumstances (it is not easy to predict when
1173 just by looking at oldname and newname, unfortunately). In these
1174 cases, renaming through a temporary name avoids the problem.
1176 A second problem on Win95 is that renaming through a temp name when
1177 newname is uppercase fails (the final long name ends up in
1178 lowercase, although the short alias might be uppercase) UNLESS the
1179 long temp name is not 8.3.
1181 So, on Win95 we always rename through a temp name, and we make sure
1182 the temp name has a long extension to ensure correct renaming. */
1184 strcpy (temp, map_win32_filename (oldname, NULL));
1186 if (GetVersion () & 0x80000000)
1190 if (p = strrchr (temp, '\\'))
1194 /* Force temp name to require a manufactured 8.3 alias - this
1195 seems to make the second rename work properly. */
1196 strcpy (p, "_rename_temp.XXXXXX");
1198 if (rename (map_win32_filename (oldname, NULL), temp) < 0)
1202 /* Emulate Unix behavior - newname is deleted if it already exists
1203 (at least if it is a file; don't do this for directories).
1204 However, don't do this if we are just changing the case of the file
1205 name - we will end up deleting the file we are trying to rename! */
1206 newname = map_win32_filename (newname, NULL);
1208 /* TODO: Use GetInformationByHandle (on NT) to ensure newname and temp
1209 do not refer to the same file, eg. through share aliases. */
1210 if (stricmp (newname, temp) != 0
1211 && (attr = GetFileAttributes (newname)) != -1
1212 && (attr & FILE_ATTRIBUTE_DIRECTORY) == 0)
1214 _chmod (newname, 0666);
1218 return rename (temp, newname);
1222 static FILETIME utc_base_ft;
1223 static int init = 0;
1227 static long double utc_base;
1230 convert_time (FILETIME ft)
1236 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
1245 st.wMilliseconds = 0;
1247 SystemTimeToFileTime (&st, &utc_base_ft);
1248 utc_base = (long double) utc_base_ft.dwHighDateTime
1249 * 4096 * 1024 * 1024 + utc_base_ft.dwLowDateTime;
1253 if (CompareFileTime (&ft, &utc_base_ft) < 0)
1256 ret = (long double) ft.dwHighDateTime * 4096 * 1024 * 1024 + ft.dwLowDateTime;
1258 return (time_t) (ret * 1e-7);
1262 static LARGE_INTEGER utc_base_li;
1265 convert_time (FILETIME uft)
1272 TIME_ZONE_INFORMATION tzi;
1280 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
1289 st.wMilliseconds = 0;
1291 SystemTimeToFileTime (&st, &utc_base_ft);
1293 utc_base_li.LowPart = utc_base_ft.dwLowDateTime;
1294 utc_base_li.HighPart = utc_base_ft.dwHighDateTime;
1301 /* On a compiler that supports long integers, do it the easy way */
1302 lft.LowPart = uft.dwLowDateTime;
1303 lft.HighPart = uft.dwHighDateTime;
1304 ret = (time_t) ((lft.QuadPart - utc_base_li.QuadPart) / 10000000);
1308 /* Do it the hard way using mktime. */
1309 FileTimeToLocalFileTime(&uft, &ft);
1310 FileTimeToSystemTime (&ft, &st);
1311 tzid = GetTimeZoneInformation (&tzi);
1312 t.tm_year = st.wYear - 1900;
1313 t.tm_mon = st.wMonth - 1;
1314 t.tm_mday = st.wDay;
1315 t.tm_hour = st.wHour;
1316 t.tm_min = st.wMinute;
1317 t.tm_sec = st.wSecond;
1318 t.tm_isdst = (tzid == TIME_ZONE_ID_DAYLIGHT);
1319 /* st.wMilliseconds not applicable */
1333 /* in case we ever have need of this */
1335 convert_from_time_t (time_t time, FILETIME * pft)
1341 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
1350 st.wMilliseconds = 0;
1352 SystemTimeToFileTime (&st, &utc_base_ft);
1353 utc_base = (long double) utc_base_ft.dwHighDateTime
1354 * 4096 * 1024 * 1024 + utc_base_ft.dwLowDateTime;
1358 /* time in 100ns units since 1-Jan-1601 */
1359 tmp = (long double) time * 1e7 + utc_base;
1360 pft->dwHighDateTime = (DWORD) (tmp / (4096.0 * 1024 * 1024));
1361 pft->dwLowDateTime = (DWORD) (tmp - pft->dwHighDateTime);
1366 /* No reason to keep this; faking inode values either by hashing or even
1367 using the file index from GetInformationByHandle, is not perfect and
1368 so by default Emacs doesn't use the inode values on Windows.
1369 Instead, we now determine file-truename correctly (except for
1370 possible drive aliasing etc). */
1372 /* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
1374 hashval (const unsigned char * str)
1379 h = (h << 4) + *str++;
1385 /* Return the hash value of the canonical pathname, excluding the
1386 drive/UNC header, to get a hopefully unique inode number. */
1388 generate_inode_val (const char * name)
1390 char fullname[ MAX_PATH ];
1394 /* Get the truly canonical filename, if it exists. (Note: this
1395 doesn't resolve aliasing due to subst commands, or recognize hard
1397 if (!win32_get_long_filename ((char *)name, fullname, MAX_PATH))
1400 parse_root (fullname, &p);
1401 /* Normal Win32 filesystems are still case insensitive. */
1408 /* stat has been fixed since MSVC 5.0.
1409 Oh, and do not encapsulater stat for non-MS compilers, too */
1410 /* #### popineau@ese-metz.fr says they still might be broken.
1411 Oh well... Let's add that `1 ||' condition.... --kkm */
1412 #if 1 || defined(_MSC_VER) && _MSC_VER < 1100
1414 /* Since stat is encapsulated on Windows NT, we need to encapsulate
1415 the equally broken fstat as well. */
1417 fstat (int handle, struct stat *buffer)
1420 BY_HANDLE_FILE_INFORMATION lpFileInfo;
1421 /* Initialize values */
1422 buffer->st_mode = 0;
1423 buffer->st_size = 0;
1425 buffer->st_rdev = 0;
1426 buffer->st_atime = 0;
1427 buffer->st_ctime = 0;
1428 buffer->st_mtime = 0;
1429 buffer->st_nlink = 0;
1430 ret = GetFileInformationByHandle((HANDLE) _get_osfhandle(handle), &lpFileInfo);
1437 buffer->st_mtime = convert_time (lpFileInfo.ftLastWriteTime);
1438 buffer->st_atime = convert_time (lpFileInfo.ftLastAccessTime);
1439 if (buffer->st_atime == 0) buffer->st_atime = buffer->st_mtime;
1440 buffer->st_ctime = convert_time (lpFileInfo.ftCreationTime);
1441 if (buffer->st_ctime == 0) buffer->st_ctime = buffer->st_mtime;
1442 buffer->st_size = lpFileInfo.nFileSizeLow;
1443 buffer->st_nlink = (short) lpFileInfo.nNumberOfLinks;
1448 /* MSVC stat function can't cope with UNC names and has other bugs, so
1449 replace it with our own. This also allows us to calculate consistent
1450 inode values without hacks in the main Emacs code. */
1452 stat (const char * path, struct stat * buf)
1455 WIN32_FIND_DATA wfd;
1460 int rootdir = FALSE;
1462 if (path == NULL || buf == NULL)
1468 name = (char *) map_win32_filename (path, &path);
1469 /* must be valid filename, no wild cards */
1470 if (strchr (name, '*') || strchr (name, '?'))
1476 /* Remove trailing directory separator, unless name is the root
1477 directory of a drive or UNC volume in which case ensure there
1478 is a trailing separator. */
1479 len = strlen (name);
1480 rootdir = (path >= name + len - 1
1481 && (IS_DIRECTORY_SEP (*path) || *path == 0));
1482 name = strcpy (alloca (len + 2), name);
1486 if (!IS_DIRECTORY_SEP (name[len-1]))
1487 strcat (name, "\\");
1488 if (GetDriveType (name) < 2)
1493 memset (&wfd, 0, sizeof (wfd));
1494 wfd.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
1495 wfd.ftCreationTime = utc_base_ft;
1496 wfd.ftLastAccessTime = utc_base_ft;
1497 wfd.ftLastWriteTime = utc_base_ft;
1498 strcpy (wfd.cFileName, name);
1502 if (IS_DIRECTORY_SEP (name[len-1]))
1505 /* (This is hacky, but helps when doing file completions on
1506 network drives.) Optimize by using information available from
1507 active readdir if possible. */
1508 if (dir_find_handle != INVALID_HANDLE_VALUE &&
1509 (len = strlen (dir_pathname)),
1510 strnicmp (name, dir_pathname, len) == 0 &&
1511 IS_DIRECTORY_SEP (name[len]) &&
1512 stricmp (name + len + 1, dir_static.d_name) == 0)
1514 /* This was the last entry returned by readdir. */
1515 wfd = dir_find_data;
1519 fh = FindFirstFile (name, &wfd);
1520 if (fh == INVALID_HANDLE_VALUE)
1529 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1531 buf->st_mode = _S_IFDIR;
1532 buf->st_nlink = 2; /* doesn't really matter */
1533 fake_inode = 0; /* this doesn't either I think */
1535 else if (!NILP (Vmswindows_get_true_file_attributes))
1537 /* This is more accurate in terms of getting the correct number
1538 of links, but is quite slow (it is noticeable when Emacs is
1539 making a list of file name completions). */
1540 BY_HANDLE_FILE_INFORMATION info;
1542 /* No access rights required to get info. */
1543 fh = CreateFile (name, 0, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
1544 OPEN_EXISTING, 0, NULL);
1546 if (GetFileInformationByHandle (fh, &info))
1548 switch (GetFileType (fh))
1550 case FILE_TYPE_DISK:
1551 buf->st_mode = _S_IFREG;
1553 case FILE_TYPE_PIPE:
1554 buf->st_mode = _S_IFIFO;
1556 case FILE_TYPE_CHAR:
1557 case FILE_TYPE_UNKNOWN:
1559 buf->st_mode = _S_IFCHR;
1561 buf->st_nlink = (short) info.nNumberOfLinks;
1562 /* Might as well use file index to fake inode values, but this
1563 is not guaranteed to be unique unless we keep a handle open
1564 all the time (even then there are situations where it is
1565 not unique). Reputedly, there are at most 48 bits of info
1566 (on NTFS, presumably less on FAT). */
1567 fake_inode = info.nFileIndexLow ^ info.nFileIndexHigh;
1578 /* Don't bother to make this information more accurate. */
1579 buf->st_mode = _S_IFREG;
1585 /* Not sure if there is any point in this. */
1586 if (!NILP (Vwin32_generate_fake_inodes))
1587 fake_inode = generate_inode_val (name);
1588 else if (fake_inode == 0)
1590 /* For want of something better, try to make everything unique. */
1591 static DWORD gen_num = 0;
1592 fake_inode = ++gen_num;
1596 /* #### MSVC defines _ino_t to be short; other libc's might not. */
1597 buf->st_ino = (unsigned short) (fake_inode ^ (fake_inode >> 16));
1599 /* consider files to belong to current user */
1600 buf->st_uid = buf->st_gid = nt_fake_unix_uid;
1602 /* volume_info is set indirectly by map_win32_filename */
1603 buf->st_dev = volume_info.serialnum;
1604 buf->st_rdev = volume_info.serialnum;
1606 buf->st_size = wfd.nFileSizeLow;
1608 /* Convert timestamps to Unix format. */
1609 buf->st_mtime = convert_time (wfd.ftLastWriteTime);
1610 buf->st_atime = convert_time (wfd.ftLastAccessTime);
1611 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
1612 buf->st_ctime = convert_time (wfd.ftCreationTime);
1613 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
1615 /* determine rwx permissions */
1616 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
1617 permission = _S_IREAD;
1619 permission = _S_IREAD | _S_IWRITE;
1621 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1622 permission |= _S_IEXEC;
1625 char * p = strrchr (name, '.');
1627 (stricmp (p, ".exe") == 0 ||
1628 stricmp (p, ".com") == 0 ||
1629 stricmp (p, ".bat") == 0 ||
1630 stricmp (p, ".cmd") == 0))
1631 permission |= _S_IEXEC;
1634 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
1638 #endif /* defined(_MSC_VER) && _MSC_VER < 1100 */
1640 /* From callproc.c */
1641 extern Lisp_Object Vbinary_process_input;
1642 extern Lisp_Object Vbinary_process_output;
1644 /* Unix pipe() has only one arg */
1646 sys_pipe (int * phandles)
1651 /* make pipe handles non-inheritable; when we spawn a child, we
1652 replace the relevant handle with an inheritable one. Also put
1653 pipes into binary mode; we will do text mode translation ourselves
1655 rc = _pipe (phandles, 0, _O_NOINHERIT | _O_BINARY);
1659 flags = FILE_PIPE | FILE_READ;
1660 if (!NILP (Vbinary_process_output))
1661 flags |= FILE_BINARY;
1662 fd_info[phandles[0]].flags = flags;
1664 flags = FILE_PIPE | FILE_WRITE;
1665 if (!NILP (Vbinary_process_input))
1666 flags |= FILE_BINARY;
1667 fd_info[phandles[1]].flags = flags;
1674 term_ntproc (int unused)
1681 /* Initial preparation for subprocess support: replace our standard
1682 handles with non-inheritable versions. */
1685 HANDLE stdin_save = INVALID_HANDLE_VALUE;
1686 HANDLE stdout_save = INVALID_HANDLE_VALUE;
1687 HANDLE stderr_save = INVALID_HANDLE_VALUE;
1689 parent = GetCurrentProcess ();
1691 /* ignore errors when duplicating and closing; typically the
1692 handles will be invalid when running as a gui program. */
1693 DuplicateHandle (parent,
1694 GetStdHandle (STD_INPUT_HANDLE),
1699 DUPLICATE_SAME_ACCESS);
1701 DuplicateHandle (parent,
1702 GetStdHandle (STD_OUTPUT_HANDLE),
1707 DUPLICATE_SAME_ACCESS);
1709 DuplicateHandle (parent,
1710 GetStdHandle (STD_ERROR_HANDLE),
1715 DUPLICATE_SAME_ACCESS);
1721 if (stdin_save != INVALID_HANDLE_VALUE)
1722 _open_osfhandle ((long) stdin_save, O_TEXT);
1724 _open ("nul", O_TEXT | O_NOINHERIT | O_RDONLY);
1727 if (stdout_save != INVALID_HANDLE_VALUE)
1728 _open_osfhandle ((long) stdout_save, O_TEXT);
1730 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
1733 if (stderr_save != INVALID_HANDLE_VALUE)
1734 _open_osfhandle ((long) stderr_save, O_TEXT);
1736 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
1740 /* unfortunately, atexit depends on implementation of malloc */
1741 /* atexit (term_ntproc); */
1742 signal (SIGABRT, term_ntproc);
1744 /* determine which drives are fixed, for GetCachedVolumeInformation */
1746 /* GetDriveType must have trailing backslash. */
1747 char drive[] = "A:\\";
1749 /* Loop over all possible drive letters */
1750 while ( *drive <= 'Z' )
1752 /* Record if this drive letter refers to a fixed drive. */
1753 fixed_drives[ DRIVE_INDEX (*drive) ] =
1754 (GetDriveType (drive) == DRIVE_FIXED);
1762 tty_semi_canonicalize_console_connection (Lisp_Object connection,
1763 Error_behavior errb)
1769 tty_canonicalize_console_connection (Lisp_Object connection,
1770 Error_behavior errb)
1776 tty_semi_canonicalize_device_connection (Lisp_Object connection,
1777 Error_behavior errb)
1783 tty_canonicalize_device_connection (Lisp_Object connection,
1784 Error_behavior errb)
1790 /*--------------------------------------------------------------------*/
1791 /* Signal support */
1792 /*--------------------------------------------------------------------*/
1794 /* We need MS-defined signal and raise here */
1798 #define sigmask(nsig) (1U << nsig)
1800 /* We can support as many signals as fit into word */
1803 /* Signal handlers. Initial value = 0 = SIG_DFL */
1804 static void (__cdecl *signal_handlers[SIG_MAX])(int) = {0};
1806 /* Signal block mask: bit set to 1 means blocked */
1807 unsigned signal_block_mask = 0;
1809 /* Signal pending mask: bit set to 1 means sig is pending */
1810 unsigned signal_pending_mask = 0;
1812 msw_sighandler msw_sigset (int nsig, msw_sighandler handler)
1814 /* We delegate some signals to the system function */
1815 if (nsig == SIGFPE || nsig == SIGABRT || nsig == SIGINT)
1816 return signal (nsig, handler);
1818 if (nsig < 0 || nsig > SIG_MAX)
1824 /* Store handler ptr */
1826 msw_sighandler old_handler = signal_handlers[nsig];
1827 signal_handlers[nsig] = handler;
1832 int msw_sighold (int nsig)
1834 if (nsig < 0 || nsig > SIG_MAX)
1835 return errno = EINVAL;
1837 signal_block_mask |= sigmask(nsig);
1841 int msw_sigrelse (int nsig)
1843 if (nsig < 0 || nsig > SIG_MAX)
1844 return errno = EINVAL;
1846 signal_block_mask &= ~sigmask(nsig);
1848 if (signal_pending_mask & sigmask(nsig))
1854 int msw_sigpause (int nsig)
1856 /* This is currently not called, because the only
1857 call to sigpause inside XEmacs is with SIGCHLD
1858 parameter. Just in case, we put an assert here,
1859 so anyone who will add a call to sigpause will
1860 be surprised (or surprise someone else...) */
1865 int msw_raise (int nsig)
1867 /* We delegate some raises to the system routine */
1868 if (nsig == SIGFPE || nsig == SIGABRT || nsig == SIGINT)
1869 return raise (nsig);
1871 if (nsig < 0 || nsig > SIG_MAX)
1872 return errno = EINVAL;
1874 /* If the signal is blocked, remember to issue later */
1875 if (signal_block_mask & sigmask(nsig))
1877 signal_pending_mask |= sigmask(nsig);
1881 if (signal_handlers[nsig] == SIG_IGN)
1884 if (signal_handlers[nsig] != SIG_DFL)
1886 (*signal_handlers[nsig])(nsig);
1890 /* Default signal actions */
1891 if (nsig == SIGALRM || nsig == SIGPROF)
1894 /* Other signals are ignored by default */
1898 /*--------------------------------------------------------------------*/
1900 /*--------------------------------------------------------------------*/
1902 /* We emulate two timers, one for SIGALRM, another for SIGPROF.
1904 itimerproc() function has an implementation limitation: it does
1905 not allow to set *both* interval and period. If an attempt is
1906 made to set both, and then they are unequal, the function
1909 Minimum timer resolution on Win32 systems varies, and is greater
1910 than or equal than 1 ms. The resolution is always wrapped not to
1911 attempt to get below the system defined limit.
1914 /* Timer precision, denominator of one fraction: for 100 ms
1915 interval, request 10 ms precision
1917 const int timer_prec = 10;
1919 /* Last itimervals, as set by calls to setitimer */
1920 static struct itimerval it_alarm;
1921 static struct itimerval it_prof;
1923 /* Timer IDs as returned by MM */
1924 MMRESULT tid_alarm = 0;
1925 MMRESULT tid_prof = 0;
1927 static void CALLBACK timer_proc (UINT uID, UINT uMsg, DWORD dwUser,
1928 DWORD dw1, DWORD dw2)
1930 /* Just raise a signal indicated by dwUser parameter */
1934 /* Divide time in ms specified by IT by DENOM. Return 1 ms
1935 if division results in zero */
1936 static UINT period (const struct itimerval* it, UINT denom)
1938 static TIMECAPS time_caps;
1941 const struct timeval* tv =
1942 (it->it_value.tv_sec == 0 && it->it_value.tv_usec == 0)
1943 ? &it->it_interval : &it->it_value;
1945 /* Zero means stop timer */
1946 if (tv->tv_sec == 0 && tv->tv_usec == 0)
1949 /* Convert to ms and divide by denom */
1950 res = (tv->tv_sec * 1000 + (tv->tv_usec + 500) / 1000) / denom;
1952 /* Converge to minimum timer resolution */
1953 if (time_caps.wPeriodMin == 0)
1954 timeGetDevCaps (&time_caps, sizeof(time_caps));
1956 if (res < time_caps.wPeriodMin)
1957 res = time_caps.wPeriodMin;
1962 static int setitimer_helper (const struct itimerval* itnew,
1963 struct itimerval* itold, struct itimerval* itcurrent,
1964 MMRESULT* tid, DWORD sigkind)
1966 UINT delay, resolution, event_type;
1968 /* First stop the old timer */
1971 timeKillEvent (*tid);
1972 timeEndPeriod (period (itcurrent, timer_prec));
1976 /* Return old itimerval if requested */
1978 *itold = *itcurrent;
1980 *itcurrent = *itnew;
1982 /* Determine if to start new timer */
1983 delay = period (itnew, 1);
1986 resolution = period (itnew, timer_prec);
1987 event_type = (itnew->it_value.tv_sec == 0 && itnew->it_value.tv_usec == 0)
1988 ? TIME_ONESHOT : TIME_PERIODIC;
1989 timeBeginPeriod (resolution);
1990 *tid = timeSetEvent (delay, resolution, timer_proc, sigkind, event_type);
1993 return !delay || *tid;
1996 int setitimer (int kind, const struct itimerval* itnew,
1997 struct itimerval* itold)
1999 /* In this version, both interval and value are allowed
2000 only if they are equal. */
2001 assert ((itnew->it_value.tv_sec == 0 && itnew->it_value.tv_usec == 0)
2002 || (itnew->it_interval.tv_sec == 0 && itnew->it_interval.tv_usec == 0)
2003 || (itnew->it_value.tv_sec == itnew->it_interval.tv_sec &&
2004 itnew->it_value.tv_usec == itnew->it_interval.tv_usec));
2006 if (kind == ITIMER_REAL)
2007 return setitimer_helper (itnew, itold, &it_alarm, &tid_alarm, SIGALRM);
2008 else if (kind == ITIMER_PROF)
2009 return setitimer_helper (itnew, itold, &it_prof, &tid_prof, SIGPROF);
2011 return errno = EINVAL;
2015 open_input_file (file_data *p_file, CONST char *filename)
2018 HANDLE file_mapping;
2020 DWORD size, upper_size;
2022 file = CreateFile (filename, GENERIC_READ, FILE_SHARE_READ, NULL,
2023 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
2024 if (file == INVALID_HANDLE_VALUE)
2027 size = GetFileSize (file, &upper_size);
2028 file_mapping = CreateFileMapping (file, NULL, PAGE_READONLY,
2033 file_base = MapViewOfFile (file_mapping, FILE_MAP_READ, 0, 0, size);
2037 p_file->name = (char*)filename;
2038 p_file->size = size;
2039 p_file->file = file;
2040 p_file->file_mapping = file_mapping;
2041 p_file->file_base = file_base;
2046 /* Close the system structures associated with the given file. */
2048 close_file_data (file_data *p_file)
2050 UnmapViewOfFile (p_file->file_base);
2051 CloseHandle (p_file->file_mapping);
2052 CloseHandle (p_file->file);
2058 DEFVAR_INT ("nt-fake-unix-uid", &nt_fake_unix_uid /*
2059 *Set uid returned by `user-uid' and `user-real-uid'.
2060 Under NT and 9x, there is no uids, and even no almighty user called root.
2061 By setting this variable, you can have any uid of choice. Default is 0.
2062 Changes to this variable take effect immediately.
2064 nt_fake_unix_uid = 0;