1 /* Utility and Unix shadow routines for GNU Emacs on Windows NT.
2 Copyright (C) 1994, 1995 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
6 GNU Emacs 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 later
11 GNU Emacs 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 for
16 You should have received a copy of the GNU General Public License along
17 with GNU Emacs; see the file COPYING. If not, write to the Free Software
18 Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
20 Geoff Voelker (voelker@cs.washington.edu) 7-29-94
23 /* Define stat before including config.h. */
27 nt_stat (char *filename
, struct stat
*statbuf
)
29 int r
, l
= strlen (filename
);
31 extern long *xmalloc ();
34 /* stat has a bug when passed a name of a directory with a trailing
35 backslash (but a trailing forward slash works fine). */
36 if (filename
[l
- 1] == '\\')
38 str
= (char *) xmalloc (l
+ 1);
39 strcpy (str
, filename
);
41 r
= stat (str
, statbuf
);
46 return stat (filename
, statbuf
);
49 /* Place a wrapper around the NT version of ctime. It returns NULL
50 on network directories, so we handle that case here.
51 Define it before including config.h. (Ulrich Leodolter, 1/11/95). */
53 nt_ctime (const time_t *t
)
55 char *str
= (char *) ctime (t
);
56 return (str
? str
: "Sun Jan 01 00:00:00 1970");
76 extern int report_file_error (char *, Lisp_Object
);
78 /* Get the current working directory. */
82 return GetCurrentDirectory (MAXPATHLEN
, dir
);
85 /* Emulate gethostname. */
87 gethostname (char *buffer
, int size
)
89 /* NT only allows small host names, so the buffer is
90 certainly large enough. */
91 return !GetComputerName (buffer
, &size
);
94 /* Emulate getloadavg. */
96 getloadavg (double loadavg
[], int nelem
)
100 /* A faithful emulation is going to have to be saved for a rainy day. */
101 for (i
= 0; i
< nelem
; i
++)
108 /* Emulate sleep...we could have done this with a define, but that
109 would necessitate including windows.h in the files that used it.
110 This is much easier. */
112 nt_sleep (int seconds
)
114 Sleep (seconds
* 1000);
117 /* Emulate the Unix directory procedures opendir, closedir,
118 and readdir. We can't use the procedures supplied in sysdep.c,
119 so we provide them here. */
121 struct direct dir_static
; /* simulated directory contents */
122 static int dir_finding
;
123 static HANDLE dir_find_handle
;
126 opendir (char *filename
)
130 /* Opening is done by FindFirstFile. However, a read is inherent to
131 this operation, so we have a flag to handle the open at read
132 time. This flag essentially means "there is a find-handle open and
133 it needs to be closed." */
135 if (!(dirp
= (DIR *) malloc (sizeof (DIR))))
144 /* This is tacky, but we need the directory name for our
145 implementation of readdir. */
146 strncpy (dirp
->dd_buf
, filename
, DIRBLKSIZ
);
153 /* If we have a find-handle open, close it. */
156 FindClose (dir_find_handle
);
159 xfree ((char *) dirp
);
165 WIN32_FIND_DATA find_data
;
167 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
170 char filename
[MAXNAMLEN
+ 3];
173 strncpy (filename
, dirp
->dd_buf
, MAXNAMLEN
);
174 ln
= strlen (filename
)-1;
175 if (filename
[ln
] != '\\' && filename
[ln
] != ':')
176 strcat (filename
, "\\");
177 strcat (filename
, "*.*");
179 dir_find_handle
= FindFirstFile (filename
, &find_data
);
181 if (dir_find_handle
== INVALID_HANDLE_VALUE
)
188 if (!FindNextFile (dir_find_handle
, &find_data
))
192 /* NT's unique ID for a file is 64 bits, so we have to fake it here.
193 This should work as long as we never use 0. */
194 dir_static
.d_ino
= 1;
196 dir_static
.d_reclen
= sizeof (struct direct
) - MAXNAMLEN
+ 3 +
197 dir_static
.d_namlen
- dir_static
.d_namlen
% 4;
199 dir_static
.d_namlen
= strlen (find_data
.cFileName
);
200 strncpy (dir_static
.d_name
, find_data
.cFileName
, MAXNAMLEN
);
205 /* Emulate getpwuid and getpwnam. */
207 int getuid (); /* forward declaration */
209 #define PASSWD_FIELD_SIZE 256
211 static char the_passwd_name
[PASSWD_FIELD_SIZE
];
212 static char the_passwd_passwd
[PASSWD_FIELD_SIZE
];
213 static char the_passwd_gecos
[PASSWD_FIELD_SIZE
];
214 static char the_passwd_dir
[PASSWD_FIELD_SIZE
];
215 static char the_passwd_shell
[PASSWD_FIELD_SIZE
];
217 static struct passwd the_passwd
=
232 int size
= PASSWD_FIELD_SIZE
;
234 if (!GetUserName (the_passwd
.pw_name
, &size
))
237 the_passwd
.pw_passwd
[0] = '\0';
238 the_passwd
.pw_uid
= 0;
239 the_passwd
.pw_gid
= 0;
240 strcpy (the_passwd
.pw_gecos
, the_passwd
.pw_name
);
241 the_passwd
.pw_dir
[0] = '\0';
242 the_passwd
.pw_shell
[0] = '\0';
248 getpwnam (char *name
)
252 pw
= getpwuid (getuid ());
256 if (strcmp (name
, pw
->pw_name
))
263 /* We don't have scripts to automatically determine the system configuration
264 for Emacs before it's compiled, and we don't want to have to make the
265 user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
268 static char configuration_buffer
[32];
271 get_emacs_configuration (void)
273 char *arch
, *oem
, *os
;
275 /* Determine the processor type. */
276 switch (get_processor_type ())
279 #ifdef PROCESSOR_INTEL_386
280 case PROCESSOR_INTEL_386
:
281 case PROCESSOR_INTEL_486
:
282 case PROCESSOR_INTEL_PENTIUM
:
287 #ifdef PROCESSOR_INTEL_860
288 case PROCESSOR_INTEL_860
:
293 #ifdef PROCESSOR_MIPS_R2000
294 case PROCESSOR_MIPS_R2000
:
295 case PROCESSOR_MIPS_R3000
:
296 case PROCESSOR_MIPS_R4000
:
301 #ifdef PROCESSOR_ALPHA_21064
302 case PROCESSOR_ALPHA_21064
:
312 /* Let oem be "*" until we figure out how to decode the OEM field. */
321 sprintf (configuration_buffer
, "%s-%s-%s%d.%d", arch
, oem
, os
,
322 get_nt_major_version (), get_nt_minor_version ());
323 return configuration_buffer
;
326 /* Conjure up inode and device numbers that will serve the purpose
327 of Emacs. Return 1 upon success, 0 upon failure. */
329 get_inode_and_device_vals (Lisp_Object filename
, Lisp_Object
*p_inode
,
330 Lisp_Object
*p_device
)
332 /* File uids on NT are found using a handle to a file, which
333 implies that it has been opened. Since we want to be able
334 to stat an arbitrary file, we must open it, get the info,
337 Also, NT file uids are 64-bits. This is a problem. */
342 BY_HANDLE_FILE_INFORMATION info
;
344 /* We have to stat files and directories differently, so check
345 to see what filename references. */
346 attrs
= GetFileAttributes (XSTRING (filename
)->data
);
347 if (attrs
== 0xFFFFFFFF) {
350 if (attrs
& FILE_ATTRIBUTE_DIRECTORY
) {
351 /* Conjure up bogus, but unique, values. */
352 attrs
= GetTickCount ();
353 *p_inode
= make_number (attrs
);
354 *p_device
= make_number (attrs
);
358 /* FIXME: It shouldn't be opened without READ access, but NT on x86
359 doesn't allow GetFileInfo in that case (NT on mips does). */
361 handle
= CreateFile (XSTRING (filename
)->data
,
363 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
366 FILE_ATTRIBUTE_NORMAL
,
368 if (handle
== INVALID_HANDLE_VALUE
)
371 result
= GetFileInformationByHandle (handle
, &info
);
372 CloseHandle (handle
);
376 *p_inode
= make_number (info
.nFileIndexLow
); /* use the low value */
377 *p_device
= make_number (info
.dwVolumeSerialNumber
);
382 /* The following pipe routines are used to support our fork emulation.
383 Since NT's crt dup always creates inherited handles, we
384 must be careful in setting up pipes. First create
385 non-inherited pipe handles, then create an inherited handle
386 to the write end by dup-ing it, and then close the non-inherited
387 end that was just duped. This gives us one non-inherited handle
388 on the read end and one inherited handle to the write end. As
389 the parent, we close the inherited handle to the write end after
390 spawning the child. */
392 /* From callproc.c */
393 extern Lisp_Object Vbinary_process_input
;
394 extern Lisp_Object Vbinary_process_output
;
397 pipe_with_inherited_out (int fds
[2])
400 unsigned int flags
= _O_NOINHERIT
;
402 if (!NILP (Vbinary_process_output
))
405 _pipe (fds
, 0, flags
);
406 inherit_out
= dup (fds
[1]);
408 fds
[1] = inherit_out
;
412 pipe_with_inherited_in (int fds
[2])
415 unsigned int flags
= _O_NOINHERIT
;
417 if (!NILP (Vbinary_process_input
))
420 _pipe (fds
, 0, flags
);
421 inherit_in
= dup (fds
[0]);
426 /* The following two routines are used to manipulate stdin, stdout, and
427 stderr of our child processes.
429 Assuming that in, out, and err are inherited, we make them stdin,
430 stdout, and stderr of the child as follows:
432 - Save the parent's current standard handles.
433 - Set the parent's standard handles to the handles being passed in.
434 (Note that _get_osfhandle is an io.h procedure that
435 maps crt file descriptors to NT file handles.)
436 - Spawn the child, which inherits in, out, and err as stdin,
437 stdout, and stderr. (see Spawnve)
438 - Reset the parent's standard handles to the saved handles.
439 (see reset_standard_handles)
440 We assume that the caller closes in, out, and err after calling us. */
443 prepare_standard_handles (int in
, int out
, int err
, HANDLE handles
[4])
445 HANDLE parent
, stdin_save
, stdout_save
, stderr_save
, err_handle
;
448 /* The Win95 beta doesn't set the standard handles correctly.
449 Handicap subprocesses until we get a version that works correctly.
450 Undefining the subprocesses macro reveals other incompatibilities,
451 so, since we're expecting subprocs to work in the near future,
452 disable them here. */
453 report_file_error ("Subprocesses currently disabled on Win95", Qnil
);
456 parent
= GetCurrentProcess ();
457 stdin_save
= GetStdHandle (STD_INPUT_HANDLE
);
458 stdout_save
= GetStdHandle (STD_OUTPUT_HANDLE
);
459 stderr_save
= GetStdHandle (STD_ERROR_HANDLE
);
462 if (!DuplicateHandle (parent
,
463 GetStdHandle (STD_INPUT_HANDLE
),
468 DUPLICATE_SAME_ACCESS
))
469 report_file_error ("Duplicating parent's input handle", Qnil
);
471 if (!DuplicateHandle (parent
,
472 GetStdHandle (STD_OUTPUT_HANDLE
),
477 DUPLICATE_SAME_ACCESS
))
478 report_file_error ("Duplicating parent's output handle", Qnil
);
480 if (!DuplicateHandle (parent
,
481 GetStdHandle (STD_ERROR_HANDLE
),
486 DUPLICATE_SAME_ACCESS
))
487 report_file_error ("Duplicating parent's error handle", Qnil
);
488 #endif /* !HAVE_NTGUI */
490 if (!SetStdHandle (STD_INPUT_HANDLE
, (HANDLE
) _get_osfhandle (in
)))
491 report_file_error ("Changing stdin handle", Qnil
);
493 if (!SetStdHandle (STD_OUTPUT_HANDLE
, (HANDLE
) _get_osfhandle (out
)))
494 report_file_error ("Changing stdout handle", Qnil
);
496 /* We lose data if we use the same handle to the pipe for stdout and
497 stderr, so make a duplicate. This took a while to find. */
500 if (!DuplicateHandle (parent
,
501 (HANDLE
) _get_osfhandle (err
),
506 DUPLICATE_SAME_ACCESS
))
507 report_file_error ("Duplicating out handle to make err handle.",
512 err_handle
= (HANDLE
) _get_osfhandle (err
);
515 if (!SetStdHandle (STD_ERROR_HANDLE
, err_handle
))
516 report_file_error ("Changing stderr handle", Qnil
);
518 handles
[0] = stdin_save
;
519 handles
[1] = stdout_save
;
520 handles
[2] = stderr_save
;
521 handles
[3] = err_handle
;
525 reset_standard_handles (int in
, int out
, int err
, HANDLE handles
[4])
527 HANDLE stdin_save
= handles
[0];
528 HANDLE stdout_save
= handles
[1];
529 HANDLE stderr_save
= handles
[2];
530 HANDLE err_handle
= handles
[3];
534 if (!SetStdHandle (STD_INPUT_HANDLE
, stdin_save
))
535 report_file_error ("Resetting input handle", Qnil
);
537 if (!SetStdHandle (STD_OUTPUT_HANDLE
, stdout_save
))
540 report_file_error ("Resetting output handle", Qnil
);
543 if (!SetStdHandle (STD_ERROR_HANDLE
, stderr_save
))
544 report_file_error ("Resetting error handle", Qnil
);
545 #endif /* !HAVE_NTGUI */
549 /* If out and err are the same handle, then we duplicated out
550 and stuck it in err_handle. Close the duplicate to clean up. */
551 if (!CloseHandle (err_handle
))
552 report_file_error ("Closing error handle duplicated from out.",
560 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
561 return ((rand () << 15) | rand ());
570 /* Destructively turn backslashes into slashes. */
572 dostounix_filename (p
)
583 /* Routines that are no-ops on NT but are defined to get Emacs to compile. */
587 sigsetmask (int signal_mask
)
599 kill (int pid
, int signal
)
605 setpgrp (int pid
, int gid
)
617 unrequest_sigio (void)
640 /* Remove all CR's that are followed by a LF.
641 (From msdos.c...probably should figure out a way to share it,
642 although this code isn't going to ever change.) */
646 register unsigned char *buf
;
648 unsigned char *np
= buf
;
649 unsigned char *startp
= buf
;
650 unsigned char *endp
= buf
+ n
;
654 while (buf
< endp
- 1)
658 if (*(++buf
) != 0x0a)
669 #define REG_ROOT "SOFTWARE\\GNU\\Emacs\\"
672 nt_get_resource (key
, lpdwtype
)
677 HKEY hrootkey
= NULL
;
681 /* Check both the current user and the local machine to see if
682 we have any resources. */
684 if (RegOpenKeyEx (HKEY_CURRENT_USER
, REG_ROOT
, 0, KEY_READ
, &hrootkey
) == ERROR_SUCCESS
)
688 if (RegQueryValueEx (hrootkey
, key
, NULL
, NULL
, NULL
, &cbData
) == ERROR_SUCCESS
689 && (lpvalue
= (LPBYTE
) xmalloc (cbData
)) != NULL
690 && RegQueryValueEx (hrootkey
, key
, NULL
, lpdwtype
, lpvalue
, &cbData
) == ERROR_SUCCESS
)
695 if (lpvalue
) xfree (lpvalue
);
697 RegCloseKey (hrootkey
);
700 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE
, REG_ROOT
, 0, KEY_READ
, &hrootkey
) == ERROR_SUCCESS
)
704 if (RegQueryValueEx (hrootkey
, key
, NULL
, NULL
, NULL
, &cbData
) == ERROR_SUCCESS
&&
705 (lpvalue
= (LPBYTE
) xmalloc (cbData
)) != NULL
&&
706 RegQueryValueEx (hrootkey
, key
, NULL
, lpdwtype
, lpvalue
, &cbData
) == ERROR_SUCCESS
)
711 if (lpvalue
) xfree (lpvalue
);
713 RegCloseKey (hrootkey
);
722 /* Open a console window to display messages during dumping. */
726 /* Check for environment variables and use registry if they don't exist */
732 static char * env_vars
[] =
745 for (i
= 0; i
< (sizeof (env_vars
) / sizeof (env_vars
[0])); i
++)
747 if (!getenv (env_vars
[i
]) &&
748 (lpval
= nt_get_resource (env_vars
[i
], &dwType
)) != NULL
)
750 if (dwType
== REG_EXPAND_SZ
)
752 char buf1
[500], buf2
[500];
754 ExpandEnvironmentStrings ((LPSTR
) lpval
, buf1
, 500);
755 _snprintf (buf2
, 499, "%s=%s", env_vars
[i
], buf1
);
756 putenv (strdup (buf2
));
758 else if (dwType
== REG_SZ
)
762 _snprintf (buf
, 499, "%s=%s", env_vars
[i
], lpval
);
763 putenv (strdup (buf
));
773 #include <sys/timeb.h>
775 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
777 gettimeofday (struct timeval
*tv
, struct timezone
*tz
)
782 tv
->tv_sec
= tb
.time
;
783 tv
->tv_usec
= tb
.millitm
* 1000L;
786 tz
->tz_minuteswest
= tb
.timezone
; /* minutes west of Greenwich */
787 tz
->tz_dsttime
= tb
.dstflag
; /* type of dst correction */
790 #endif /* HAVE_TIMEVAL */
794 Keep
this around
...we might need it later
.
798 * Find the user's real name by opening the process token and looking
799 * up the name associated with the user-sid in that token.
802 char b
[256], Name
[256], RefD
[256];
803 DWORD length
= 256, rlength
= 256, trash
;
808 Vuser_real_login_name
= build_string ("foo");
809 else if (!OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY
, &Token
))
811 Vuser_real_login_name
= build_string ("unknown");
813 else if (!GetTokenInformation (Token
, TokenUser
, (PVOID
)b
, 256,
817 Vuser_real_login_name
= build_string ("unknown");
819 else if (!LookupAccountSid ((void *)0, (PSID
)b
, Name
, &length
, RefD
,
823 Vuser_real_login_name
= build_string ("unknown");
826 Vuser_real_login_name
= build_string (Name
);
828 #else /* not WINDOWSNT */
829 #endif /* not WINDOWSNT */