9803
|
1 /* Utility and Unix shadow routines for GNU Emacs on Windows NT.
|
|
2 Copyright (C) 1994 Free Software Foundation, Inc.
|
|
3
|
|
4 This file is part of GNU Emacs.
|
|
5
|
|
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 1, or (at your option) any later
|
|
9 version.
|
|
10
|
|
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
|
|
14 more details.
|
|
15
|
|
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.
|
|
19
|
|
20 Geoff Voelker (voelker@cs.washington.edu) 7-29-94
|
|
21 */
|
|
22
|
|
23 #include <windows.h>
|
|
24 #include <stdlib.h>
|
|
25 #include <stdio.h>
|
|
26 #include <io.h>
|
|
27 #include <fcntl.h>
|
|
28 #include <ctype.h>
|
|
29
|
|
30 #include "config.h"
|
|
31 #define getwd _getwd
|
|
32 #include "lisp.h"
|
|
33 #undef getwd
|
|
34
|
|
35 #include <pwd.h>
|
|
36
|
|
37 #include "ndir.h"
|
|
38 #include "ntheap.h"
|
|
39
|
|
40 extern int report_file_error (char *, Lisp_Object);
|
|
41
|
|
42 /* Get the current working directory. */
|
|
43 int
|
|
44 getwd (char *dir)
|
|
45 {
|
|
46 return GetCurrentDirectory (MAXPATHLEN, dir);
|
|
47 }
|
|
48
|
|
49 /* Emulate gethostname. */
|
|
50 int
|
|
51 gethostname (char *buffer, int size)
|
|
52 {
|
|
53 /* NT only allows small host names, so the buffer is
|
|
54 certainly large enough. */
|
|
55 return !GetComputerName (buffer, &size);
|
|
56 }
|
|
57
|
|
58 /* Emulate getloadavg. */
|
|
59 int
|
|
60 getloadavg (double loadavg[], int nelem)
|
|
61 {
|
|
62 int i;
|
|
63
|
|
64 /* A faithful emulation is going to have to be saved for a rainy day. */
|
|
65 for (i = 0; i < nelem; i++)
|
|
66 {
|
|
67 loadavg[i] = 0.0;
|
|
68 }
|
|
69 return i;
|
|
70 }
|
|
71
|
|
72 /* Emulate sleep...we could have done this with a define, but that
|
|
73 would necessitate including windows.h in the files that used it.
|
|
74 This is much easier. */
|
|
75 void
|
|
76 nt_sleep (int seconds)
|
|
77 {
|
|
78 Sleep (seconds * 1000);
|
|
79 }
|
|
80
|
|
81 /* Emulate the Unix directory procedures opendir, closedir,
|
|
82 and readdir. We can't use the procedures supplied in sysdep.c,
|
|
83 so we provide them here. */
|
|
84
|
|
85 struct direct dir_static; /* simulated directory contents */
|
|
86 static int dir_finding;
|
|
87 static HANDLE dir_find_handle;
|
|
88
|
|
89 DIR *
|
|
90 opendir (char *filename)
|
|
91 {
|
|
92 DIR *dirp;
|
|
93
|
|
94 /* Opening is done by FindFirstFile. However, a read is inherent to
|
|
95 this operation, so we have a flag to handle the open at read
|
|
96 time. This flag essentially means "there is a find-handle open and
|
|
97 it needs to be closed." */
|
|
98
|
|
99 if (!(dirp = (DIR *) malloc (sizeof (DIR))))
|
|
100 {
|
|
101 return 0;
|
|
102 }
|
|
103
|
|
104 dirp->dd_fd = 0;
|
|
105 dirp->dd_loc = 0;
|
|
106 dirp->dd_size = 0;
|
|
107
|
|
108 /* This is tacky, but we need the directory name for our
|
|
109 implementation of readdir. */
|
|
110 strncpy (dirp->dd_buf, filename, DIRBLKSIZ);
|
|
111 return dirp;
|
|
112 }
|
|
113
|
|
114 void
|
|
115 closedir (DIR *dirp)
|
|
116 {
|
|
117 /* If we have a find-handle open, close it. */
|
|
118 if (dir_finding)
|
|
119 {
|
|
120 FindClose (dir_find_handle);
|
|
121 dir_finding = 0;
|
|
122 }
|
|
123 xfree ((char *) dirp);
|
|
124 }
|
|
125
|
|
126 struct direct *
|
|
127 readdir (DIR *dirp)
|
|
128 {
|
|
129 WIN32_FIND_DATA find_data;
|
|
130
|
|
131 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
|
|
132 if (!dir_finding)
|
|
133 {
|
|
134 char filename[MAXNAMLEN + 3];
|
|
135 int ln;
|
|
136
|
|
137 strncpy (filename, dirp->dd_buf, MAXNAMLEN);
|
|
138 ln = strlen (filename)-1;
|
|
139 if (filename[ln] != '\\' && filename[ln] != ':')
|
|
140 strcat (filename, "\\");
|
|
141 strcat (filename, "*.*");
|
|
142
|
|
143 dir_find_handle = FindFirstFile (filename, &find_data);
|
|
144
|
|
145 if (dir_find_handle == INVALID_HANDLE_VALUE)
|
|
146 return NULL;
|
|
147
|
|
148 dir_finding = 1;
|
|
149 }
|
|
150 else
|
|
151 {
|
|
152 if (!FindNextFile (dir_find_handle, &find_data))
|
|
153 return NULL;
|
|
154 }
|
|
155
|
|
156 /* Don't return . or .. since it doesn't look like any of the
|
|
157 readdir calling code expects them. */
|
|
158 while (strcmp (find_data.cFileName, ".") == 0
|
|
159 || strcmp (find_data.cFileName, "..") == 0)
|
|
160 {
|
|
161 if (!FindNextFile (dir_find_handle, &find_data))
|
|
162 return 0;
|
|
163 }
|
|
164
|
|
165 /* NT's unique ID for a file is 64 bits, so we have to fake it here.
|
|
166 This should work as long as we never use 0. */
|
|
167 dir_static.d_ino = 1;
|
|
168
|
|
169 dir_static.d_reclen = sizeof (struct direct) - MAXNAMLEN + 3 +
|
|
170 dir_static.d_namlen - dir_static.d_namlen % 4;
|
|
171
|
|
172 dir_static.d_namlen = strlen (find_data.cFileName);
|
|
173 strncpy (dir_static.d_name, find_data.cFileName, MAXNAMLEN);
|
|
174
|
|
175 return &dir_static;
|
|
176 }
|
|
177
|
|
178 /* Emulate getpwuid and getpwnam. */
|
|
179
|
|
180 int getuid (); /* forward declaration */
|
|
181
|
|
182 static char the_passwd_name[256];
|
|
183 static char the_passwd_passwd[256];
|
|
184 static char the_passwd_gecos[256];
|
|
185 static char the_passwd_dir[256];
|
|
186 static char the_passwd_shell[256];
|
|
187
|
|
188 static struct passwd the_passwd =
|
|
189 {
|
|
190 the_passwd_name,
|
|
191 the_passwd_passwd,
|
|
192 0,
|
|
193 0,
|
|
194 0,
|
|
195 the_passwd_gecos,
|
|
196 the_passwd_dir,
|
|
197 the_passwd_shell,
|
|
198 };
|
|
199
|
|
200 struct passwd *
|
|
201 getpwuid (int uid)
|
|
202 {
|
|
203 int size = 256;
|
|
204
|
|
205 if (!GetUserName (the_passwd.pw_name, &size))
|
|
206 return NULL;
|
|
207
|
|
208 the_passwd.pw_passwd[0] = '\0';
|
|
209 the_passwd.pw_uid = 0;
|
|
210 the_passwd.pw_gid = 0;
|
|
211 strcpy (the_passwd.pw_gecos, the_passwd.pw_name);
|
|
212 the_passwd.pw_dir[0] = '\0';
|
|
213 the_passwd.pw_shell[0] = '\0';
|
|
214
|
|
215 return &the_passwd;
|
|
216 }
|
|
217
|
|
218 struct passwd *
|
|
219 getpwnam (char *name)
|
|
220 {
|
|
221 struct passwd *pw;
|
|
222
|
|
223 pw = getpwuid (getuid ());
|
|
224 if (!pw)
|
|
225 return pw;
|
|
226
|
|
227 if (strcmp (name, pw->pw_name))
|
|
228 return NULL;
|
|
229
|
|
230 return pw;
|
|
231 }
|
|
232
|
|
233
|
|
234 /* We don't have scripts to automatically determine the system configuration
|
|
235 for Emacs before it's compiled, and we don't want to have to make the
|
|
236 user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
|
|
237 routine. */
|
|
238
|
|
239 static char configuration_buffer[16];
|
|
240
|
|
241 char *
|
|
242 get_emacs_configuration (void)
|
|
243 {
|
|
244 char *arch, *oem;
|
|
245
|
|
246 /* Determine the processor type. */
|
|
247 switch (get_processor_type ())
|
|
248 {
|
|
249 case PROCESSOR_INTEL_386:
|
|
250 case PROCESSOR_INTEL_486:
|
|
251 case PROCESSOR_INTEL_PENTIUM:
|
|
252 arch = "i386";
|
|
253 break;
|
|
254 case PROCESSOR_INTEL_860:
|
|
255 arch = "i860";
|
|
256 break;
|
|
257 case PROCESSOR_MIPS_R2000:
|
|
258 case PROCESSOR_MIPS_R3000:
|
|
259 case PROCESSOR_MIPS_R4000:
|
|
260 arch = "mips";
|
|
261 break;
|
|
262 case PROCESSOR_ALPHA_21064:
|
|
263 arch = "alpha";
|
|
264 break;
|
|
265 default:
|
|
266 arch = "unknown";
|
|
267 break;
|
|
268 }
|
|
269
|
|
270 /* Let oem be "*" until we figure out how to decode the OEM field. */
|
|
271 oem = "*";
|
|
272
|
|
273 sprintf (configuration_buffer, "%s-%s-nt%d.%d", arch, oem,
|
|
274 get_nt_major_version (), get_nt_minor_version ());
|
|
275 return configuration_buffer;
|
|
276 }
|
|
277
|
|
278 /* Conjure up inode and device numbers that will serve the purpose
|
|
279 of Emacs. Return 1 upon success, 0 upon failure. */
|
|
280 int
|
|
281 get_inode_and_device_vals (Lisp_Object filename, Lisp_Object *p_inode,
|
|
282 Lisp_Object *p_device)
|
|
283 {
|
|
284 /* File uids on NT are found using a handle to a file, which
|
|
285 implies that it has been opened. Since we want to be able
|
|
286 to stat an arbitrary file, we must open it, get the info,
|
|
287 and then close it.
|
|
288
|
|
289 Also, NT file uids are 64-bits. This is a problem. */
|
|
290
|
|
291 HANDLE handle;
|
|
292 BOOL result;
|
|
293 BY_HANDLE_FILE_INFORMATION info;
|
|
294
|
|
295 /* FIXME: It shouldn't be opened without READ access, but NT on x86
|
|
296 doesn't allow GetFileInfo in that case (NT on mips does). */
|
|
297
|
|
298 handle = CreateFile (XSTRING (filename)->data,
|
|
299 GENERIC_READ,
|
|
300 FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
301 NULL,
|
|
302 OPEN_EXISTING,
|
|
303 FILE_ATTRIBUTE_NORMAL,
|
|
304 NULL);
|
|
305 if (handle == INVALID_HANDLE_VALUE)
|
|
306 return 0;
|
|
307
|
|
308 result = GetFileInformationByHandle (handle, &info);
|
|
309 CloseHandle (handle);
|
|
310 if (!result)
|
|
311 return 0;
|
|
312
|
|
313 *p_inode = make_number (info.nFileIndexLow); /* use the low value */
|
|
314 *p_device = make_number (info.dwVolumeSerialNumber);
|
|
315
|
|
316 return 1;
|
|
317 }
|
|
318
|
|
319 /* The following pipe routines are used to support our fork emulation.
|
|
320 Since NT's crt dup always creates inherited handles, we
|
|
321 must be careful in setting up pipes. First create
|
|
322 non-inherited pipe handles, then create an inherited handle
|
|
323 to the write end by dup-ing it, and then close the non-inherited
|
|
324 end that was just duped. This gives us one non-inherited handle
|
|
325 on the read end and one inherited handle to the write end. As
|
|
326 the parent, we close the inherited handle to the write end after
|
|
327 spawning the child. */
|
|
328
|
|
329 /* From callproc.c */
|
|
330 extern Lisp_Object Vbinary_process_input;
|
|
331 extern Lisp_Object Vbinary_process_output;
|
|
332
|
|
333 void
|
|
334 pipe_with_inherited_out (int fds[2])
|
|
335 {
|
|
336 int inherit_out;
|
|
337 unsigned int flags = _O_NOINHERIT;
|
|
338
|
|
339 if (!NILP (Vbinary_process_output))
|
|
340 flags |= _O_BINARY;
|
|
341
|
|
342 _pipe (fds, 0, flags);
|
|
343 inherit_out = dup (fds[1]);
|
|
344 close (fds[1]);
|
|
345 fds[1] = inherit_out;
|
|
346 }
|
|
347
|
|
348 void
|
|
349 pipe_with_inherited_in (int fds[2])
|
|
350 {
|
|
351 int inherit_in;
|
|
352 unsigned int flags = _O_NOINHERIT;
|
|
353
|
|
354 if (!NILP (Vbinary_process_input))
|
|
355 flags |= _O_BINARY;
|
|
356
|
|
357 _pipe (fds, 0, flags);
|
|
358 inherit_in = dup (fds[0]);
|
|
359 close (fds[0]);
|
|
360 fds[0] = inherit_in;
|
|
361 }
|
|
362
|
|
363 /* The following two routines are used to manipulate stdin, stdout, and
|
|
364 stderr of our child processes.
|
|
365
|
|
366 Assuming that in, out, and err are inherited, we make them stdin,
|
|
367 stdout, and stderr of the child as follows:
|
|
368
|
|
369 - Save the parent's current standard handles.
|
|
370 - Set the parent's standard handles to the handles being passed in.
|
|
371 (Note that _get_osfhandle is an io.h procedure that
|
|
372 maps crt file descriptors to NT file handles.)
|
|
373 - Spawn the child, which inherits in, out, and err as stdin,
|
|
374 stdout, and stderr. (see Spawnve)
|
|
375 - Reset the parent's standard handles to the saved handles.
|
|
376 (see reset_standard_handles)
|
|
377 We assume that the caller closes in, out, and err after calling us. */
|
|
378
|
|
379 void
|
|
380 prepare_standard_handles (int in, int out, int err, HANDLE handles[4])
|
|
381 {
|
|
382 HANDLE parent, stdin_save, stdout_save, stderr_save, err_handle;
|
|
383
|
|
384 parent = GetCurrentProcess ();
|
|
385 if (!DuplicateHandle (parent,
|
|
386 GetStdHandle (STD_INPUT_HANDLE),
|
|
387 parent,
|
|
388 &stdin_save,
|
|
389 0,
|
|
390 FALSE,
|
|
391 DUPLICATE_SAME_ACCESS))
|
|
392 report_file_error ("Duplicating parent's input handle", Qnil);
|
|
393
|
|
394 if (!DuplicateHandle (parent,
|
|
395 GetStdHandle (STD_OUTPUT_HANDLE),
|
|
396 parent,
|
|
397 &stdout_save,
|
|
398 0,
|
|
399 FALSE,
|
|
400 DUPLICATE_SAME_ACCESS))
|
|
401 report_file_error ("Duplicating parent's output handle", Qnil);
|
|
402
|
|
403 if (!DuplicateHandle (parent,
|
|
404 GetStdHandle (STD_ERROR_HANDLE),
|
|
405 parent,
|
|
406 &stderr_save,
|
|
407 0,
|
|
408 FALSE,
|
|
409 DUPLICATE_SAME_ACCESS))
|
|
410 report_file_error ("Duplicating parent's error handle", Qnil);
|
|
411
|
|
412 if (!SetStdHandle (STD_INPUT_HANDLE, (HANDLE) _get_osfhandle (in)))
|
|
413 report_file_error ("Changing stdin handle", Qnil);
|
|
414
|
|
415 if (!SetStdHandle (STD_OUTPUT_HANDLE, (HANDLE) _get_osfhandle (out)))
|
|
416 report_file_error ("Changing stdout handle", Qnil);
|
|
417
|
|
418 /* We lose data if we use the same handle to the pipe for stdout and
|
|
419 stderr, so make a duplicate. This took a while to find. */
|
|
420 if (out == err)
|
|
421 {
|
|
422 if (!DuplicateHandle (parent,
|
|
423 (HANDLE) _get_osfhandle (err),
|
|
424 parent,
|
|
425 &err_handle,
|
|
426 0,
|
|
427 TRUE,
|
|
428 DUPLICATE_SAME_ACCESS))
|
|
429 report_file_error ("Duplicating out handle to make err handle.",
|
|
430 Qnil);
|
|
431 }
|
|
432 else
|
|
433 {
|
|
434 err_handle = (HANDLE) _get_osfhandle (err);
|
|
435 }
|
|
436
|
|
437 if (!SetStdHandle (STD_ERROR_HANDLE, err_handle))
|
|
438 report_file_error ("Changing stderr handle", Qnil);
|
|
439
|
|
440 handles[0] = stdin_save;
|
|
441 handles[1] = stdout_save;
|
|
442 handles[2] = stderr_save;
|
|
443 handles[3] = err_handle;
|
|
444 }
|
|
445
|
|
446 void
|
|
447 reset_standard_handles (int in, int out, int err, HANDLE handles[4])
|
|
448 {
|
|
449 HANDLE stdin_save = handles[0];
|
|
450 HANDLE stdout_save = handles[1];
|
|
451 HANDLE stderr_save = handles[2];
|
|
452 HANDLE err_handle = handles[3];
|
|
453
|
|
454 if (!SetStdHandle (STD_INPUT_HANDLE, stdin_save))
|
|
455 report_file_error ("Resetting input handle", Qnil);
|
|
456
|
|
457 if (!SetStdHandle (STD_OUTPUT_HANDLE, stdout_save))
|
|
458 report_file_error ("Resetting output handle", Qnil);
|
|
459
|
|
460 if (!SetStdHandle (STD_ERROR_HANDLE, stderr_save))
|
|
461 report_file_error ("Resetting error handle", Qnil);
|
|
462
|
|
463 if (out == err)
|
|
464 {
|
|
465 /* If out and err are the same handle, then we duplicated out
|
|
466 and stuck it in err_handle. Close the duplicate to clean up. */
|
|
467 if (!CloseHandle (err_handle))
|
|
468 report_file_error ("Closing error handle duplicated from out.",
|
|
469 Qnil);
|
|
470 }
|
|
471 }
|
|
472
|
|
473 /* Destructively turn backslashes into slashes. */
|
|
474 void
|
|
475 dostounix_filename (p)
|
|
476 register char *p;
|
|
477 {
|
|
478 while (*p)
|
|
479 {
|
|
480 if (*p == '\\')
|
|
481 *p = '/';
|
|
482 p++;
|
|
483 }
|
|
484 }
|
|
485
|
|
486 /* Routines that are no-ops on NT but are defined to get Emacs to compile. */
|
|
487
|
|
488
|
|
489 int
|
|
490 sigsetmask (int signal_mask)
|
|
491 {
|
|
492 return 0;
|
|
493 }
|
|
494
|
|
495 int
|
|
496 sigblock (int sig)
|
|
497 {
|
|
498 return 0;
|
|
499 }
|
|
500
|
|
501 int
|
|
502 kill (int pid, int signal)
|
|
503 {
|
|
504 return 0;
|
|
505 }
|
|
506
|
|
507 int
|
|
508 setpgrp (int pid, int gid)
|
|
509 {
|
|
510 return 0;
|
|
511 }
|
|
512
|
|
513 int
|
|
514 alarm (int seconds)
|
|
515 {
|
|
516 return 0;
|
|
517 }
|
|
518
|
|
519 int
|
|
520 unrequest_sigio (void)
|
|
521 {
|
|
522 return 0;
|
|
523 }
|
|
524
|
|
525 int
|
|
526 request_sigio (void)
|
|
527 {
|
|
528 return 0;
|
|
529 }
|
|
530
|
|
531 int
|
|
532 getuid ()
|
|
533 {
|
|
534 return 0;
|
|
535 }
|
|
536
|
|
537 int
|
|
538 geteuid ()
|
|
539 {
|
|
540 return 0;
|
|
541 }
|
|
542
|
|
543 /* Remove all CR's that are followed by a LF.
|
|
544 (From msdos.c...probably should figure out a way to share it,
|
|
545 although this code isn't going to ever change.) */
|
|
546 int
|
|
547 crlf_to_lf (n, buf)
|
|
548 register int n;
|
|
549 register unsigned char *buf;
|
|
550 {
|
|
551 unsigned char *np = buf;
|
|
552 unsigned char *startp = buf;
|
|
553 unsigned char *endp = buf + n;
|
|
554
|
|
555 if (n == 0)
|
|
556 return n;
|
|
557 while (buf < endp - 1)
|
|
558 {
|
|
559 if (*buf == 0x0d)
|
|
560 {
|
|
561 if (*(++buf) != 0x0a)
|
|
562 *np++ = 0x0d;
|
|
563 }
|
|
564 else
|
|
565 *np++ = *buf++;
|
|
566 }
|
|
567 if (buf < endp)
|
|
568 *np++ = *buf++;
|
|
569 return np - startp;
|
|
570 }
|
|
571
|
|
572
|
|
573 #ifdef PIGSFLY
|
|
574 Keep this around...we might need it later.
|
|
575 #ifdef WINDOWSNT
|
|
576 {
|
|
577 /*
|
|
578 * Find the user's real name by opening the process token and looking
|
|
579 * up the name associated with the user-sid in that token.
|
|
580 */
|
|
581
|
|
582 char b[256], Name[256], RefD[256];
|
|
583 DWORD length = 256, rlength = 256, trash;
|
|
584 HANDLE Token;
|
|
585 SID_NAME_USE User;
|
|
586
|
|
587 if (1)
|
|
588 Vuser_real_name = build_string ("foo");
|
|
589 else if (!OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY, &Token))
|
|
590 {
|
|
591 Vuser_real_name = build_string ("unknown");
|
|
592 }
|
|
593 else if (!GetTokenInformation (Token, TokenUser, (PVOID)b, 256,
|
|
594 &trash))
|
|
595 {
|
|
596 CloseHandle (Token);
|
|
597 Vuser_real_name = build_string ("unknown");
|
|
598 }
|
|
599 else if (!LookupAccountSid ((void *)0, (PSID)b, Name, &length, RefD,
|
|
600 &rlength, &User))
|
|
601 {
|
|
602 CloseHandle (Token);
|
|
603 Vuser_real_name = build_string ("unknown");
|
|
604 }
|
|
605 else
|
|
606 Vuser_real_name = build_string (Name);
|
|
607 }
|
|
608 #else /* not WINDOWSNT */
|
|
609 #endif /* not WINDOWSNT */
|
|
610 #endif /* PIGSFLY */
|