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 static char the_passwd_name
[256];
210 static char the_passwd_passwd
[256];
211 static char the_passwd_gecos
[256];
212 static char the_passwd_dir
[256];
213 static char the_passwd_shell
[256];
215 static struct passwd the_passwd
=
232 if (!GetUserName (the_passwd
.pw_name
, &size
))
235 the_passwd
.pw_passwd
[0] = '\0';
236 the_passwd
.pw_uid
= 0;
237 the_passwd
.pw_gid
= 0;
238 strcpy (the_passwd
.pw_gecos
, the_passwd
.pw_name
);
239 the_passwd
.pw_dir
[0] = '\0';
240 the_passwd
.pw_shell
[0] = '\0';
246 getpwnam (char *name
)
250 pw
= getpwuid (getuid ());
254 if (strcmp (name
, pw
->pw_name
))
261 /* We don't have scripts to automatically determine the system configuration
262 for Emacs before it's compiled, and we don't want to have to make the
263 user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
266 static char configuration_buffer
[16];
269 get_emacs_configuration (void)
273 /* Determine the processor type. */
274 switch (get_processor_type ())
276 case PROCESSOR_INTEL_386
:
277 case PROCESSOR_INTEL_486
:
278 case PROCESSOR_INTEL_PENTIUM
:
281 case PROCESSOR_INTEL_860
:
284 case PROCESSOR_MIPS_R2000
:
285 case PROCESSOR_MIPS_R3000
:
286 case PROCESSOR_MIPS_R4000
:
289 case PROCESSOR_ALPHA_21064
:
297 /* Let oem be "*" until we figure out how to decode the OEM field. */
300 sprintf (configuration_buffer
, "%s-%s-nt%d.%d", arch
, oem
,
301 get_nt_major_version (), get_nt_minor_version ());
302 return configuration_buffer
;
305 /* Conjure up inode and device numbers that will serve the purpose
306 of Emacs. Return 1 upon success, 0 upon failure. */
308 get_inode_and_device_vals (Lisp_Object filename
, Lisp_Object
*p_inode
,
309 Lisp_Object
*p_device
)
311 /* File uids on NT are found using a handle to a file, which
312 implies that it has been opened. Since we want to be able
313 to stat an arbitrary file, we must open it, get the info,
316 Also, NT file uids are 64-bits. This is a problem. */
321 BY_HANDLE_FILE_INFORMATION info
;
323 /* We have to stat files and directories differently, so check
324 to see what filename references. */
325 attrs
= GetFileAttributes (XSTRING (filename
)->data
);
326 if (attrs
== 0xFFFFFFFF) {
329 if (attrs
& FILE_ATTRIBUTE_DIRECTORY
) {
330 /* Conjure up bogus, but unique, values. */
331 attrs
= GetTickCount ();
332 *p_inode
= make_number (attrs
);
333 *p_device
= make_number (attrs
);
337 /* FIXME: It shouldn't be opened without READ access, but NT on x86
338 doesn't allow GetFileInfo in that case (NT on mips does). */
340 handle
= CreateFile (XSTRING (filename
)->data
,
342 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
345 FILE_ATTRIBUTE_NORMAL
,
347 if (handle
== INVALID_HANDLE_VALUE
)
350 result
= GetFileInformationByHandle (handle
, &info
);
351 CloseHandle (handle
);
355 *p_inode
= make_number (info
.nFileIndexLow
); /* use the low value */
356 *p_device
= make_number (info
.dwVolumeSerialNumber
);
361 /* The following pipe routines are used to support our fork emulation.
362 Since NT's crt dup always creates inherited handles, we
363 must be careful in setting up pipes. First create
364 non-inherited pipe handles, then create an inherited handle
365 to the write end by dup-ing it, and then close the non-inherited
366 end that was just duped. This gives us one non-inherited handle
367 on the read end and one inherited handle to the write end. As
368 the parent, we close the inherited handle to the write end after
369 spawning the child. */
371 /* From callproc.c */
372 extern Lisp_Object Vbinary_process_input
;
373 extern Lisp_Object Vbinary_process_output
;
376 pipe_with_inherited_out (int fds
[2])
379 unsigned int flags
= _O_NOINHERIT
;
381 if (!NILP (Vbinary_process_output
))
384 _pipe (fds
, 0, flags
);
385 inherit_out
= dup (fds
[1]);
387 fds
[1] = inherit_out
;
391 pipe_with_inherited_in (int fds
[2])
394 unsigned int flags
= _O_NOINHERIT
;
396 if (!NILP (Vbinary_process_input
))
399 _pipe (fds
, 0, flags
);
400 inherit_in
= dup (fds
[0]);
405 /* The following two routines are used to manipulate stdin, stdout, and
406 stderr of our child processes.
408 Assuming that in, out, and err are inherited, we make them stdin,
409 stdout, and stderr of the child as follows:
411 - Save the parent's current standard handles.
412 - Set the parent's standard handles to the handles being passed in.
413 (Note that _get_osfhandle is an io.h procedure that
414 maps crt file descriptors to NT file handles.)
415 - Spawn the child, which inherits in, out, and err as stdin,
416 stdout, and stderr. (see Spawnve)
417 - Reset the parent's standard handles to the saved handles.
418 (see reset_standard_handles)
419 We assume that the caller closes in, out, and err after calling us. */
422 prepare_standard_handles (int in
, int out
, int err
, HANDLE handles
[4])
424 HANDLE parent
, stdin_save
, stdout_save
, stderr_save
, err_handle
;
426 parent
= GetCurrentProcess ();
427 if (!DuplicateHandle (parent
,
428 GetStdHandle (STD_INPUT_HANDLE
),
433 DUPLICATE_SAME_ACCESS
))
434 report_file_error ("Duplicating parent's input handle", Qnil
);
436 if (!DuplicateHandle (parent
,
437 GetStdHandle (STD_OUTPUT_HANDLE
),
442 DUPLICATE_SAME_ACCESS
))
443 report_file_error ("Duplicating parent's output handle", Qnil
);
445 if (!DuplicateHandle (parent
,
446 GetStdHandle (STD_ERROR_HANDLE
),
451 DUPLICATE_SAME_ACCESS
))
452 report_file_error ("Duplicating parent's error handle", Qnil
);
454 if (!SetStdHandle (STD_INPUT_HANDLE
, (HANDLE
) _get_osfhandle (in
)))
455 report_file_error ("Changing stdin handle", Qnil
);
457 if (!SetStdHandle (STD_OUTPUT_HANDLE
, (HANDLE
) _get_osfhandle (out
)))
458 report_file_error ("Changing stdout handle", Qnil
);
460 /* We lose data if we use the same handle to the pipe for stdout and
461 stderr, so make a duplicate. This took a while to find. */
464 if (!DuplicateHandle (parent
,
465 (HANDLE
) _get_osfhandle (err
),
470 DUPLICATE_SAME_ACCESS
))
471 report_file_error ("Duplicating out handle to make err handle.",
476 err_handle
= (HANDLE
) _get_osfhandle (err
);
479 if (!SetStdHandle (STD_ERROR_HANDLE
, err_handle
))
480 report_file_error ("Changing stderr handle", Qnil
);
482 handles
[0] = stdin_save
;
483 handles
[1] = stdout_save
;
484 handles
[2] = stderr_save
;
485 handles
[3] = err_handle
;
489 reset_standard_handles (int in
, int out
, int err
, HANDLE handles
[4])
491 HANDLE stdin_save
= handles
[0];
492 HANDLE stdout_save
= handles
[1];
493 HANDLE stderr_save
= handles
[2];
494 HANDLE err_handle
= handles
[3];
496 if (!SetStdHandle (STD_INPUT_HANDLE
, stdin_save
))
497 report_file_error ("Resetting input handle", Qnil
);
499 if (!SetStdHandle (STD_OUTPUT_HANDLE
, stdout_save
))
500 report_file_error ("Resetting output handle", Qnil
);
502 if (!SetStdHandle (STD_ERROR_HANDLE
, stderr_save
))
503 report_file_error ("Resetting error handle", Qnil
);
507 /* If out and err are the same handle, then we duplicated out
508 and stuck it in err_handle. Close the duplicate to clean up. */
509 if (!CloseHandle (err_handle
))
510 report_file_error ("Closing error handle duplicated from out.",
518 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
519 return ((rand () << 15) | rand ());
528 /* Destructively turn backslashes into slashes. */
530 dostounix_filename (p
)
541 /* Routines that are no-ops on NT but are defined to get Emacs to compile. */
545 sigsetmask (int signal_mask
)
557 kill (int pid
, int signal
)
563 setpgrp (int pid
, int gid
)
575 unrequest_sigio (void)
598 /* Remove all CR's that are followed by a LF.
599 (From msdos.c...probably should figure out a way to share it,
600 although this code isn't going to ever change.) */
604 register unsigned char *buf
;
606 unsigned char *np
= buf
;
607 unsigned char *startp
= buf
;
608 unsigned char *endp
= buf
+ n
;
612 while (buf
< endp
- 1)
616 if (*(++buf
) != 0x0a)
628 #include <sys/timeb.h>
630 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
632 gettimeofday (struct timeval
*tv
, struct timezone
*tz
)
637 tv
->tv_sec
= tb
.time
;
638 tv
->tv_usec
= tb
.millitm
* 1000L;
641 tz
->tz_minuteswest
= tb
.timezone
; /* minutes west of Greenwich */
642 tz
->tz_dsttime
= tb
.dstflag
; /* type of dst correction */
645 #endif /* HAVE_TIMEVAL */
649 Keep
this around
...we might need it later
.
653 * Find the user's real name by opening the process token and looking
654 * up the name associated with the user-sid in that token.
657 char b
[256], Name
[256], RefD
[256];
658 DWORD length
= 256, rlength
= 256, trash
;
663 Vuser_real_name
= build_string ("foo");
664 else if (!OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY
, &Token
))
666 Vuser_real_name
= build_string ("unknown");
668 else if (!GetTokenInformation (Token
, TokenUser
, (PVOID
)b
, 256,
672 Vuser_real_name
= build_string ("unknown");
674 else if (!LookupAccountSid ((void *)0, (PSID
)b
, Name
, &length
, RefD
,
678 Vuser_real_name
= build_string ("unknown");
681 Vuser_real_name
= build_string (Name
);
683 #else /* not WINDOWSNT */
684 #endif /* not WINDOWSNT */