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
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.
21 Geoff Voelker (voelker@cs.washington.edu) 7-29-94
25 /* Define stat before including config.h. */
30 static int is_toplevel_share_name (char *);
31 static int stat_toplevel_share (char *, void *);
34 nt_stat (char *filename
, struct stat
*statbuf
)
36 int l
= strlen (filename
);
39 /* stat has a bug when passed a name of a directory with a trailing
40 backslash (but a trailing forward slash works fine). */
41 if (filename
[l
- 1] == '\\')
43 str
= (char *) alloca (l
+ 1);
44 strcpy (str
, filename
);
46 return stat (str
, statbuf
);
49 if (stat (filename
, statbuf
) == 0)
51 else if (is_toplevel_share_name (filename
))
52 return stat_toplevel_share (filename
, statbuf
);
57 /* Place a wrapper around the NT version of ctime. It returns NULL
58 on network directories, so we handle that case here.
59 Define it before including config.h. (Ulrich Leodolter, 1/11/95). */
61 nt_ctime (const time_t *t
)
63 char *str
= (char *) ctime (t
);
64 return (str
? str
: "Sun Jan 01 00:00:00 1970");
84 extern int report_file_error (char *, Lisp_Object
);
86 /* Routines for extending stat above. */
88 get_unassigned_drive_letter ()
93 mask
= GetLogicalDrives ();
94 for (i
= 0; i
< 26; i
++)
100 return (i
== 26 ? -1 : 'A' + i
);
103 void dostounix_filename (char *);
105 /* Return nonzero if NAME is of the form \\host\share (forward slashes
106 also valid), otherwise return 0. */
108 is_toplevel_share_name (char *filename
)
116 len
= strlen (filename
);
117 name
= alloca (len
+ 1);
118 strcpy (name
, filename
);
120 dostounix_filename (name
);
121 if (name
[0] != '/' || name
[1] != '/')
124 host
= strtok (&name
[2], "/");
125 share
= strtok (NULL
, "/");
126 suffix
= strtok (NULL
, "/");
127 if (!host
|| !share
|| suffix
)
134 /* FILENAME is of the form \\host\share, and stat can't handle names
135 of this form. But stat can handle \\host\share if it's been
136 assigned a drive letter. So we create a network connection to this
137 share, assign it a drive letter, stat the drive letter, and
138 disconnect from the share. Hassle... */
140 stat_toplevel_share (char *filename
, void *statbuf
)
147 drive_letter
= get_unassigned_drive_letter ();
148 if (drive_letter
< 0)
151 drive
[0] = drive_letter
;
154 net
.dwType
= RESOURCETYPE_DISK
;
155 net
.lpLocalName
= drive
;
156 net
.lpRemoteName
= filename
;
157 net
.lpProvider
= NULL
;
159 switch (WNetAddConnection2 (&net
, NULL
, NULL
, 0))
163 case ERROR_ALREADY_ASSIGNED
:
168 /* Name the toplevel directory on the drive letter. */
171 result
= stat (drive
, (void *) statbuf
);
173 /* Strip the slash so we can disconnect. */
175 if (WNetCancelConnection2 (drive
, 0, TRUE
) != NO_ERROR
)
182 /* Get the current working directory. */
186 return GetCurrentDirectory (MAXPATHLEN
, dir
);
189 /* Emulate gethostname. */
191 gethostname (char *buffer
, int size
)
193 /* NT only allows small host names, so the buffer is
194 certainly large enough. */
195 return !GetComputerName (buffer
, &size
);
198 /* Emulate getloadavg. */
200 getloadavg (double loadavg
[], int nelem
)
204 /* A faithful emulation is going to have to be saved for a rainy day. */
205 for (i
= 0; i
< nelem
; i
++)
212 /* Emulate sleep...we could have done this with a define, but that
213 would necessitate including windows.h in the files that used it.
214 This is much easier. */
216 nt_sleep (int seconds
)
218 Sleep (seconds
* 1000);
221 /* Emulate the Unix directory procedures opendir, closedir,
222 and readdir. We can't use the procedures supplied in sysdep.c,
223 so we provide them here. */
225 struct direct dir_static
; /* simulated directory contents */
226 static int dir_finding
;
227 static HANDLE dir_find_handle
;
230 opendir (char *filename
)
234 /* Opening is done by FindFirstFile. However, a read is inherent to
235 this operation, so we have a flag to handle the open at read
236 time. This flag essentially means "there is a find-handle open and
237 it needs to be closed." */
239 if (!(dirp
= (DIR *) malloc (sizeof (DIR))))
248 /* This is tacky, but we need the directory name for our
249 implementation of readdir. */
250 strncpy (dirp
->dd_buf
, filename
, DIRBLKSIZ
);
257 /* If we have a find-handle open, close it. */
260 FindClose (dir_find_handle
);
263 xfree ((char *) dirp
);
269 WIN32_FIND_DATA find_data
;
271 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
274 char filename
[MAXNAMLEN
+ 3];
277 strncpy (filename
, dirp
->dd_buf
, MAXNAMLEN
);
278 ln
= strlen (filename
)-1;
279 if (!IS_ANY_SEP (filename
[ln
]))
280 strcat (filename
, "\\");
281 strcat (filename
, "*.*");
283 dir_find_handle
= FindFirstFile (filename
, &find_data
);
285 if (dir_find_handle
== INVALID_HANDLE_VALUE
)
292 if (!FindNextFile (dir_find_handle
, &find_data
))
296 /* NT's unique ID for a file is 64 bits, so we have to fake it here.
297 This should work as long as we never use 0. */
298 dir_static
.d_ino
= 1;
300 dir_static
.d_reclen
= sizeof (struct direct
) - MAXNAMLEN
+ 3 +
301 dir_static
.d_namlen
- dir_static
.d_namlen
% 4;
303 dir_static
.d_namlen
= strlen (find_data
.cFileName
);
304 strncpy (dir_static
.d_name
, find_data
.cFileName
, MAXNAMLEN
);
309 /* Emulate getpwuid and getpwnam. */
311 int getuid (); /* forward declaration */
313 #define PASSWD_FIELD_SIZE 256
315 static char the_passwd_name
[PASSWD_FIELD_SIZE
];
316 static char the_passwd_passwd
[PASSWD_FIELD_SIZE
];
317 static char the_passwd_gecos
[PASSWD_FIELD_SIZE
];
318 static char the_passwd_dir
[PASSWD_FIELD_SIZE
];
319 static char the_passwd_shell
[PASSWD_FIELD_SIZE
];
321 static struct passwd the_passwd
=
336 int size
= PASSWD_FIELD_SIZE
;
338 if (!GetUserName (the_passwd
.pw_name
, &size
))
341 the_passwd
.pw_passwd
[0] = '\0';
342 the_passwd
.pw_uid
= 0;
343 the_passwd
.pw_gid
= 0;
344 strcpy (the_passwd
.pw_gecos
, the_passwd
.pw_name
);
345 the_passwd
.pw_dir
[0] = '\0';
346 the_passwd
.pw_shell
[0] = '\0';
352 getpwnam (char *name
)
356 pw
= getpwuid (getuid ());
360 if (strcmp (name
, pw
->pw_name
))
367 /* We don't have scripts to automatically determine the system configuration
368 for Emacs before it's compiled, and we don't want to have to make the
369 user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
372 static char configuration_buffer
[32];
375 get_emacs_configuration (void)
377 char *arch
, *oem
, *os
;
379 /* Determine the processor type. */
380 switch (get_processor_type ())
383 #ifdef PROCESSOR_INTEL_386
384 case PROCESSOR_INTEL_386
:
385 case PROCESSOR_INTEL_486
:
386 case PROCESSOR_INTEL_PENTIUM
:
391 #ifdef PROCESSOR_INTEL_860
392 case PROCESSOR_INTEL_860
:
397 #ifdef PROCESSOR_MIPS_R2000
398 case PROCESSOR_MIPS_R2000
:
399 case PROCESSOR_MIPS_R3000
:
400 case PROCESSOR_MIPS_R4000
:
405 #ifdef PROCESSOR_ALPHA_21064
406 case PROCESSOR_ALPHA_21064
:
416 /* Let oem be "*" until we figure out how to decode the OEM field. */
425 sprintf (configuration_buffer
, "%s-%s-%s%d.%d", arch
, oem
, os
,
426 get_nt_major_version (), get_nt_minor_version ());
427 return configuration_buffer
;
430 /* Conjure up inode and device numbers that will serve the purpose
431 of Emacs. Return 1 upon success, 0 upon failure. */
433 get_inode_and_device_vals (Lisp_Object filename
, Lisp_Object
*p_inode
,
434 Lisp_Object
*p_device
)
436 /* File uids on NT are found using a handle to a file, which
437 implies that it has been opened. Since we want to be able
438 to stat an arbitrary file, we must open it, get the info,
441 Also, NT file uids are 64-bits. This is a problem. */
446 BY_HANDLE_FILE_INFORMATION info
;
448 /* We have to stat files and directories differently, so check
449 to see what filename references. */
450 attrs
= GetFileAttributes (XSTRING (filename
)->data
);
451 if (attrs
== 0xFFFFFFFF) {
454 if (attrs
& FILE_ATTRIBUTE_DIRECTORY
) {
455 /* Conjure up bogus, but unique, values. */
456 attrs
= GetTickCount ();
457 *p_inode
= make_number (attrs
);
458 *p_device
= make_number (attrs
);
462 /* FIXME: It shouldn't be opened without READ access, but NT on x86
463 doesn't allow GetFileInfo in that case (NT on mips does). */
465 handle
= CreateFile (XSTRING (filename
)->data
,
467 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
470 FILE_ATTRIBUTE_NORMAL
,
472 if (handle
== INVALID_HANDLE_VALUE
)
475 result
= GetFileInformationByHandle (handle
, &info
);
476 CloseHandle (handle
);
480 *p_inode
= make_number (info
.nFileIndexLow
); /* use the low value */
481 *p_device
= make_number (info
.dwVolumeSerialNumber
);
486 /* The following pipe routines are used to support our fork emulation.
487 Since NT's crt dup always creates inherited handles, we
488 must be careful in setting up pipes. First create
489 non-inherited pipe handles, then create an inherited handle
490 to the write end by dup-ing it, and then close the non-inherited
491 end that was just duped. This gives us one non-inherited handle
492 on the read end and one inherited handle to the write end. As
493 the parent, we close the inherited handle to the write end after
494 spawning the child. */
496 /* From callproc.c */
497 extern Lisp_Object Vbinary_process_input
;
498 extern Lisp_Object Vbinary_process_output
;
501 pipe_with_inherited_out (int fds
[2])
504 unsigned int flags
= _O_NOINHERIT
;
506 if (!NILP (Vbinary_process_output
))
509 _pipe (fds
, 0, flags
);
510 inherit_out
= dup (fds
[1]);
512 fds
[1] = inherit_out
;
516 pipe_with_inherited_in (int fds
[2])
519 unsigned int flags
= _O_NOINHERIT
;
521 if (!NILP (Vbinary_process_input
))
524 _pipe (fds
, 0, flags
);
525 inherit_in
= dup (fds
[0]);
530 /* The following two routines are used to manipulate stdin, stdout, and
531 stderr of our child processes.
533 Assuming that in, out, and err are inherited, we make them stdin,
534 stdout, and stderr of the child as follows:
536 - Save the parent's current standard handles.
537 - Set the parent's standard handles to the handles being passed in.
538 (Note that _get_osfhandle is an io.h procedure that
539 maps crt file descriptors to NT file handles.)
540 - Spawn the child, which inherits in, out, and err as stdin,
541 stdout, and stderr. (see Spawnve)
542 - Reset the parent's standard handles to the saved handles.
543 (see reset_standard_handles)
544 We assume that the caller closes in, out, and err after calling us. */
547 prepare_standard_handles (int in
, int out
, int err
, HANDLE handles
[4])
549 HANDLE parent
, stdin_save
, stdout_save
, stderr_save
, err_handle
;
552 /* The Win95 beta doesn't set the standard handles correctly.
553 Handicap subprocesses until we get a version that works correctly.
554 Undefining the subprocesses macro reveals other incompatibilities,
555 so, since we're expecting subprocs to work in the near future,
556 disable them here. */
557 report_file_error ("Subprocesses currently disabled on Win95", Qnil
);
560 parent
= GetCurrentProcess ();
561 stdin_save
= GetStdHandle (STD_INPUT_HANDLE
);
562 stdout_save
= GetStdHandle (STD_OUTPUT_HANDLE
);
563 stderr_save
= GetStdHandle (STD_ERROR_HANDLE
);
566 if (!DuplicateHandle (parent
,
567 GetStdHandle (STD_INPUT_HANDLE
),
572 DUPLICATE_SAME_ACCESS
))
573 report_file_error ("Duplicating parent's input handle", Qnil
);
575 if (!DuplicateHandle (parent
,
576 GetStdHandle (STD_OUTPUT_HANDLE
),
581 DUPLICATE_SAME_ACCESS
))
582 report_file_error ("Duplicating parent's output handle", Qnil
);
584 if (!DuplicateHandle (parent
,
585 GetStdHandle (STD_ERROR_HANDLE
),
590 DUPLICATE_SAME_ACCESS
))
591 report_file_error ("Duplicating parent's error handle", Qnil
);
592 #endif /* !HAVE_NTGUI */
594 if (!SetStdHandle (STD_INPUT_HANDLE
, (HANDLE
) _get_osfhandle (in
)))
595 report_file_error ("Changing stdin handle", Qnil
);
597 if (!SetStdHandle (STD_OUTPUT_HANDLE
, (HANDLE
) _get_osfhandle (out
)))
598 report_file_error ("Changing stdout handle", Qnil
);
600 /* We lose data if we use the same handle to the pipe for stdout and
601 stderr, so make a duplicate. This took a while to find. */
604 if (!DuplicateHandle (parent
,
605 (HANDLE
) _get_osfhandle (err
),
610 DUPLICATE_SAME_ACCESS
))
611 report_file_error ("Duplicating out handle to make err handle.",
616 err_handle
= (HANDLE
) _get_osfhandle (err
);
619 if (!SetStdHandle (STD_ERROR_HANDLE
, err_handle
))
620 report_file_error ("Changing stderr handle", Qnil
);
622 handles
[0] = stdin_save
;
623 handles
[1] = stdout_save
;
624 handles
[2] = stderr_save
;
625 handles
[3] = err_handle
;
629 reset_standard_handles (int in
, int out
, int err
, HANDLE handles
[4])
631 HANDLE stdin_save
= handles
[0];
632 HANDLE stdout_save
= handles
[1];
633 HANDLE stderr_save
= handles
[2];
634 HANDLE err_handle
= handles
[3];
638 if (!SetStdHandle (STD_INPUT_HANDLE
, stdin_save
))
639 report_file_error ("Resetting input handle", Qnil
);
641 if (!SetStdHandle (STD_OUTPUT_HANDLE
, stdout_save
))
644 report_file_error ("Resetting output handle", Qnil
);
647 if (!SetStdHandle (STD_ERROR_HANDLE
, stderr_save
))
648 report_file_error ("Resetting error handle", Qnil
);
649 #endif /* !HAVE_NTGUI */
653 /* If out and err are the same handle, then we duplicated out
654 and stuck it in err_handle. Close the duplicate to clean up. */
655 if (!CloseHandle (err_handle
))
656 report_file_error ("Closing error handle duplicated from out.",
664 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
665 return ((rand () << 15) | rand ());
674 /* Destructively turn backslashes into slashes. */
676 dostounix_filename (p
)
687 /* Routines that are no-ops on NT but are defined to get Emacs to compile. */
691 sigsetmask (int signal_mask
)
703 kill (int pid
, int signal
)
709 setpgrp (int pid
, int gid
)
721 unrequest_sigio (void)
738 if (!GetUserName (buffer
, &size
))
739 /* Assume all powers upon failure. */
742 if (!stricmp ("administrator", buffer
))
745 /* A complete fabrication...is there anything to base it on? */
752 /* I could imagine arguing for checking to see whether the user is
753 in the Administrators group and returning a UID of 0 for that
754 case, but I don't know how wise that would be in the long run. */
758 /* Remove all CR's that are followed by a LF.
759 (From msdos.c...probably should figure out a way to share it,
760 although this code isn't going to ever change.) */
764 register unsigned char *buf
;
766 unsigned char *np
= buf
;
767 unsigned char *startp
= buf
;
768 unsigned char *endp
= buf
+ n
;
772 while (buf
< endp
- 1)
776 if (*(++buf
) != 0x0a)
787 #define REG_ROOT "SOFTWARE\\GNU\\Emacs\\"
790 nt_get_resource (key
, lpdwtype
)
795 HKEY hrootkey
= NULL
;
799 /* Check both the current user and the local machine to see if
800 we have any resources. */
802 if (RegOpenKeyEx (HKEY_CURRENT_USER
, REG_ROOT
, 0, KEY_READ
, &hrootkey
) == ERROR_SUCCESS
)
806 if (RegQueryValueEx (hrootkey
, key
, NULL
, NULL
, NULL
, &cbData
) == ERROR_SUCCESS
807 && (lpvalue
= (LPBYTE
) xmalloc (cbData
)) != NULL
808 && RegQueryValueEx (hrootkey
, key
, NULL
, lpdwtype
, lpvalue
, &cbData
) == ERROR_SUCCESS
)
813 if (lpvalue
) xfree (lpvalue
);
815 RegCloseKey (hrootkey
);
818 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE
, REG_ROOT
, 0, KEY_READ
, &hrootkey
) == ERROR_SUCCESS
)
822 if (RegQueryValueEx (hrootkey
, key
, NULL
, NULL
, NULL
, &cbData
) == ERROR_SUCCESS
&&
823 (lpvalue
= (LPBYTE
) xmalloc (cbData
)) != NULL
&&
824 RegQueryValueEx (hrootkey
, key
, NULL
, lpdwtype
, lpvalue
, &cbData
) == ERROR_SUCCESS
)
829 if (lpvalue
) xfree (lpvalue
);
831 RegCloseKey (hrootkey
);
840 /* Open a console window to display messages during dumping. */
844 /* Check for environment variables and use registry if they don't exist */
850 static char * env_vars
[] =
863 for (i
= 0; i
< (sizeof (env_vars
) / sizeof (env_vars
[0])); i
++)
865 if (!getenv (env_vars
[i
]) &&
866 (lpval
= nt_get_resource (env_vars
[i
], &dwType
)) != NULL
)
868 if (dwType
== REG_EXPAND_SZ
)
870 char buf1
[500], buf2
[500];
872 ExpandEnvironmentStrings ((LPSTR
) lpval
, buf1
, 500);
873 _snprintf (buf2
, 499, "%s=%s", env_vars
[i
], buf1
);
874 putenv (strdup (buf2
));
876 else if (dwType
== REG_SZ
)
880 _snprintf (buf
, 499, "%s=%s", env_vars
[i
], lpval
);
881 putenv (strdup (buf
));
891 #include <sys/timeb.h>
893 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
895 gettimeofday (struct timeval
*tv
, struct timezone
*tz
)
900 tv
->tv_sec
= tb
.time
;
901 tv
->tv_usec
= tb
.millitm
* 1000L;
904 tz
->tz_minuteswest
= tb
.timezone
; /* minutes west of Greenwich */
905 tz
->tz_dsttime
= tb
.dstflag
; /* type of dst correction */
908 #endif /* HAVE_TIMEVAL */
912 Keep
this around
...we might need it later
.
916 * Find the user's real name by opening the process token and looking
917 * up the name associated with the user-sid in that token.
920 char b
[256], Name
[256], RefD
[256];
921 DWORD length
= 256, rlength
= 256, trash
;
926 Vuser_real_login_name
= build_string ("foo");
927 else if (!OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY
, &Token
))
929 Vuser_real_login_name
= build_string ("unknown");
931 else if (!GetTokenInformation (Token
, TokenUser
, (PVOID
)b
, 256,
935 Vuser_real_login_name
= build_string ("unknown");
937 else if (!LookupAccountSid ((void *)0, (PSID
)b
, Name
, &length
, RefD
,
941 Vuser_real_login_name
= build_string ("unknown");
944 Vuser_real_login_name
= build_string (Name
);
946 #else /* not WINDOWSNT */
947 #endif /* not WINDOWSNT */