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
[32];
269 get_emacs_configuration (void)
271 char *arch
, *oem
, *os
;
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. */
306 sprintf (configuration_buffer
, "%s-%s-%s%d.%d", arch
, oem
, os
,
307 get_nt_major_version (), get_nt_minor_version ());
308 return configuration_buffer
;
311 /* Conjure up inode and device numbers that will serve the purpose
312 of Emacs. Return 1 upon success, 0 upon failure. */
314 get_inode_and_device_vals (Lisp_Object filename
, Lisp_Object
*p_inode
,
315 Lisp_Object
*p_device
)
317 /* File uids on NT are found using a handle to a file, which
318 implies that it has been opened. Since we want to be able
319 to stat an arbitrary file, we must open it, get the info,
322 Also, NT file uids are 64-bits. This is a problem. */
327 BY_HANDLE_FILE_INFORMATION info
;
329 /* We have to stat files and directories differently, so check
330 to see what filename references. */
331 attrs
= GetFileAttributes (XSTRING (filename
)->data
);
332 if (attrs
== 0xFFFFFFFF) {
335 if (attrs
& FILE_ATTRIBUTE_DIRECTORY
) {
336 /* Conjure up bogus, but unique, values. */
337 attrs
= GetTickCount ();
338 *p_inode
= make_number (attrs
);
339 *p_device
= make_number (attrs
);
343 /* FIXME: It shouldn't be opened without READ access, but NT on x86
344 doesn't allow GetFileInfo in that case (NT on mips does). */
346 handle
= CreateFile (XSTRING (filename
)->data
,
348 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
351 FILE_ATTRIBUTE_NORMAL
,
353 if (handle
== INVALID_HANDLE_VALUE
)
356 result
= GetFileInformationByHandle (handle
, &info
);
357 CloseHandle (handle
);
361 *p_inode
= make_number (info
.nFileIndexLow
); /* use the low value */
362 *p_device
= make_number (info
.dwVolumeSerialNumber
);
367 /* The following pipe routines are used to support our fork emulation.
368 Since NT's crt dup always creates inherited handles, we
369 must be careful in setting up pipes. First create
370 non-inherited pipe handles, then create an inherited handle
371 to the write end by dup-ing it, and then close the non-inherited
372 end that was just duped. This gives us one non-inherited handle
373 on the read end and one inherited handle to the write end. As
374 the parent, we close the inherited handle to the write end after
375 spawning the child. */
377 /* From callproc.c */
378 extern Lisp_Object Vbinary_process_input
;
379 extern Lisp_Object Vbinary_process_output
;
382 pipe_with_inherited_out (int fds
[2])
385 unsigned int flags
= _O_NOINHERIT
;
387 if (!NILP (Vbinary_process_output
))
390 _pipe (fds
, 0, flags
);
391 inherit_out
= dup (fds
[1]);
393 fds
[1] = inherit_out
;
397 pipe_with_inherited_in (int fds
[2])
400 unsigned int flags
= _O_NOINHERIT
;
402 if (!NILP (Vbinary_process_input
))
405 _pipe (fds
, 0, flags
);
406 inherit_in
= dup (fds
[0]);
411 /* The following two routines are used to manipulate stdin, stdout, and
412 stderr of our child processes.
414 Assuming that in, out, and err are inherited, we make them stdin,
415 stdout, and stderr of the child as follows:
417 - Save the parent's current standard handles.
418 - Set the parent's standard handles to the handles being passed in.
419 (Note that _get_osfhandle is an io.h procedure that
420 maps crt file descriptors to NT file handles.)
421 - Spawn the child, which inherits in, out, and err as stdin,
422 stdout, and stderr. (see Spawnve)
423 - Reset the parent's standard handles to the saved handles.
424 (see reset_standard_handles)
425 We assume that the caller closes in, out, and err after calling us. */
428 prepare_standard_handles (int in
, int out
, int err
, HANDLE handles
[4])
430 HANDLE parent
, stdin_save
, stdout_save
, stderr_save
, err_handle
;
433 /* The Win95 beta doesn't set the standard handles correctly.
434 Handicap subprocesses until we get a version that works correctly.
435 Undefining the subprocesses macro reveals other incompatibilities,
436 so, since we're expecting subprocs to work in the near future,
437 disable them here. */
438 report_file_error ("Subprocesses currently disabled on Win95", Qnil
);
441 parent
= GetCurrentProcess ();
442 stdin_save
= GetStdHandle (STD_INPUT_HANDLE
);
443 stdout_save
= GetStdHandle (STD_OUTPUT_HANDLE
);
444 stderr_save
= GetStdHandle (STD_ERROR_HANDLE
);
446 if (!DuplicateHandle (parent
,
447 GetStdHandle (STD_INPUT_HANDLE
),
452 DUPLICATE_SAME_ACCESS
))
453 report_file_error ("Duplicating parent's input handle", Qnil
);
455 if (!DuplicateHandle (parent
,
456 GetStdHandle (STD_OUTPUT_HANDLE
),
461 DUPLICATE_SAME_ACCESS
))
462 report_file_error ("Duplicating parent's output handle", Qnil
);
464 if (!DuplicateHandle (parent
,
465 GetStdHandle (STD_ERROR_HANDLE
),
470 DUPLICATE_SAME_ACCESS
))
471 report_file_error ("Duplicating parent's error handle", Qnil
);
473 if (!SetStdHandle (STD_INPUT_HANDLE
, (HANDLE
) _get_osfhandle (in
)))
474 report_file_error ("Changing stdin handle", Qnil
);
476 if (!SetStdHandle (STD_OUTPUT_HANDLE
, (HANDLE
) _get_osfhandle (out
)))
477 report_file_error ("Changing stdout handle", Qnil
);
479 /* We lose data if we use the same handle to the pipe for stdout and
480 stderr, so make a duplicate. This took a while to find. */
483 if (!DuplicateHandle (parent
,
484 (HANDLE
) _get_osfhandle (err
),
489 DUPLICATE_SAME_ACCESS
))
490 report_file_error ("Duplicating out handle to make err handle.",
495 err_handle
= (HANDLE
) _get_osfhandle (err
);
498 if (!SetStdHandle (STD_ERROR_HANDLE
, err_handle
))
499 report_file_error ("Changing stderr handle", Qnil
);
501 handles
[0] = stdin_save
;
502 handles
[1] = stdout_save
;
503 handles
[2] = stderr_save
;
504 handles
[3] = err_handle
;
508 reset_standard_handles (int in
, int out
, int err
, HANDLE handles
[4])
510 HANDLE stdin_save
= handles
[0];
511 HANDLE stdout_save
= handles
[1];
512 HANDLE stderr_save
= handles
[2];
513 HANDLE err_handle
= handles
[3];
516 if (!SetStdHandle (STD_INPUT_HANDLE
, stdin_save
))
517 report_file_error ("Resetting input handle", Qnil
);
519 if (!SetStdHandle (STD_OUTPUT_HANDLE
, stdout_save
))
522 report_file_error ("Resetting output handle", Qnil
);
525 if (!SetStdHandle (STD_ERROR_HANDLE
, stderr_save
))
526 report_file_error ("Resetting error handle", Qnil
);
530 /* If out and err are the same handle, then we duplicated out
531 and stuck it in err_handle. Close the duplicate to clean up. */
532 if (!CloseHandle (err_handle
))
533 report_file_error ("Closing error handle duplicated from out.",
541 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
542 return ((rand () << 15) | rand ());
551 /* Destructively turn backslashes into slashes. */
553 dostounix_filename (p
)
564 /* Routines that are no-ops on NT but are defined to get Emacs to compile. */
568 sigsetmask (int signal_mask
)
580 kill (int pid
, int signal
)
586 setpgrp (int pid
, int gid
)
598 unrequest_sigio (void)
621 /* Remove all CR's that are followed by a LF.
622 (From msdos.c...probably should figure out a way to share it,
623 although this code isn't going to ever change.) */
627 register unsigned char *buf
;
629 unsigned char *np
= buf
;
630 unsigned char *startp
= buf
;
631 unsigned char *endp
= buf
+ n
;
635 while (buf
< endp
- 1)
639 if (*(++buf
) != 0x0a)
651 #include <sys/timeb.h>
653 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
655 gettimeofday (struct timeval
*tv
, struct timezone
*tz
)
660 tv
->tv_sec
= tb
.time
;
661 tv
->tv_usec
= tb
.millitm
* 1000L;
664 tz
->tz_minuteswest
= tb
.timezone
; /* minutes west of Greenwich */
665 tz
->tz_dsttime
= tb
.dstflag
; /* type of dst correction */
668 #endif /* HAVE_TIMEVAL */
672 Keep
this around
...we might need it later
.
676 * Find the user's real name by opening the process token and looking
677 * up the name associated with the user-sid in that token.
680 char b
[256], Name
[256], RefD
[256];
681 DWORD length
= 256, rlength
= 256, trash
;
686 Vuser_real_name
= build_string ("foo");
687 else if (!OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY
, &Token
))
689 Vuser_real_name
= build_string ("unknown");
691 else if (!GetTokenInformation (Token
, TokenUser
, (PVOID
)b
, 256,
695 Vuser_real_name
= build_string ("unknown");
697 else if (!LookupAccountSid ((void *)0, (PSID
)b
, Name
, &length
, RefD
,
701 Vuser_real_name
= build_string ("unknown");
704 Vuser_real_name
= build_string (Name
);
706 #else /* not WINDOWSNT */
707 #endif /* not WINDOWSNT */