(ange-ftp-write-region, ange-ftp-insert-file-contents)
[emacs.git] / src / w32.c
blob2a091d41ae2d036d909dbc2516846e757b3579ef
1 /* Utility and Unix shadow routines for GNU Emacs on Windows NT.
2 Copyright (C) 1994 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 1, or (at your option) any later
9 version.
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.
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 #include <windows.h>
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <io.h>
27 #include <fcntl.h>
28 #include <ctype.h>
30 #include "config.h"
31 #define getwd _getwd
32 #include "lisp.h"
33 #undef getwd
35 #include <pwd.h>
37 #include "ndir.h"
38 #include "ntheap.h"
40 extern int report_file_error (char *, Lisp_Object);
42 /* Get the current working directory. */
43 int
44 getwd (char *dir)
46 return GetCurrentDirectory (MAXPATHLEN, dir);
49 /* Emulate gethostname. */
50 int
51 gethostname (char *buffer, int size)
53 /* NT only allows small host names, so the buffer is
54 certainly large enough. */
55 return !GetComputerName (buffer, &size);
58 /* Emulate getloadavg. */
59 int
60 getloadavg (double loadavg[], int nelem)
62 int i;
64 /* A faithful emulation is going to have to be saved for a rainy day. */
65 for (i = 0; i < nelem; i++)
67 loadavg[i] = 0.0;
69 return i;
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)
78 Sleep (seconds * 1000);
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. */
85 struct direct dir_static; /* simulated directory contents */
86 static int dir_finding;
87 static HANDLE dir_find_handle;
89 DIR *
90 opendir (char *filename)
92 DIR *dirp;
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." */
99 if (!(dirp = (DIR *) malloc (sizeof (DIR))))
101 return 0;
104 dirp->dd_fd = 0;
105 dirp->dd_loc = 0;
106 dirp->dd_size = 0;
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;
114 void
115 closedir (DIR *dirp)
117 /* If we have a find-handle open, close it. */
118 if (dir_finding)
120 FindClose (dir_find_handle);
121 dir_finding = 0;
123 xfree ((char *) dirp);
126 struct direct *
127 readdir (DIR *dirp)
129 WIN32_FIND_DATA find_data;
131 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
132 if (!dir_finding)
134 char filename[MAXNAMLEN + 3];
135 int ln;
137 strncpy (filename, dirp->dd_buf, MAXNAMLEN);
138 ln = strlen (filename)-1;
139 if (filename[ln] != '\\' && filename[ln] != ':')
140 strcat (filename, "\\");
141 strcat (filename, "*.*");
143 dir_find_handle = FindFirstFile (filename, &find_data);
145 if (dir_find_handle == INVALID_HANDLE_VALUE)
146 return NULL;
148 dir_finding = 1;
150 else
152 if (!FindNextFile (dir_find_handle, &find_data))
153 return NULL;
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)
161 if (!FindNextFile (dir_find_handle, &find_data))
162 return 0;
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;
169 dir_static.d_reclen = sizeof (struct direct) - MAXNAMLEN + 3 +
170 dir_static.d_namlen - dir_static.d_namlen % 4;
172 dir_static.d_namlen = strlen (find_data.cFileName);
173 strncpy (dir_static.d_name, find_data.cFileName, MAXNAMLEN);
175 return &dir_static;
178 /* Emulate getpwuid and getpwnam. */
180 int getuid (); /* forward declaration */
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];
188 static struct passwd the_passwd =
190 the_passwd_name,
191 the_passwd_passwd,
195 the_passwd_gecos,
196 the_passwd_dir,
197 the_passwd_shell,
200 struct passwd *
201 getpwuid (int uid)
203 int size = 256;
205 if (!GetUserName (the_passwd.pw_name, &size))
206 return NULL;
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';
215 return &the_passwd;
218 struct passwd *
219 getpwnam (char *name)
221 struct passwd *pw;
223 pw = getpwuid (getuid ());
224 if (!pw)
225 return pw;
227 if (strcmp (name, pw->pw_name))
228 return NULL;
230 return pw;
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. */
239 static char configuration_buffer[16];
241 char *
242 get_emacs_configuration (void)
244 char *arch, *oem;
246 /* Determine the processor type. */
247 switch (get_processor_type ())
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;
270 /* Let oem be "*" until we figure out how to decode the OEM field. */
271 oem = "*";
273 sprintf (configuration_buffer, "%s-%s-nt%d.%d", arch, oem,
274 get_nt_major_version (), get_nt_minor_version ());
275 return configuration_buffer;
278 /* Conjure up inode and device numbers that will serve the purpose
279 of Emacs. Return 1 upon success, 0 upon failure. */
281 get_inode_and_device_vals (Lisp_Object filename, Lisp_Object *p_inode,
282 Lisp_Object *p_device)
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.
289 Also, NT file uids are 64-bits. This is a problem. */
291 HANDLE handle;
292 BOOL result;
293 BY_HANDLE_FILE_INFORMATION info;
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). */
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;
308 result = GetFileInformationByHandle (handle, &info);
309 CloseHandle (handle);
310 if (!result)
311 return 0;
313 *p_inode = make_number (info.nFileIndexLow); /* use the low value */
314 *p_device = make_number (info.dwVolumeSerialNumber);
316 return 1;
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. */
329 /* From callproc.c */
330 extern Lisp_Object Vbinary_process_input;
331 extern Lisp_Object Vbinary_process_output;
333 void
334 pipe_with_inherited_out (int fds[2])
336 int inherit_out;
337 unsigned int flags = _O_NOINHERIT;
339 if (!NILP (Vbinary_process_output))
340 flags |= _O_BINARY;
342 _pipe (fds, 0, flags);
343 inherit_out = dup (fds[1]);
344 close (fds[1]);
345 fds[1] = inherit_out;
348 void
349 pipe_with_inherited_in (int fds[2])
351 int inherit_in;
352 unsigned int flags = _O_NOINHERIT;
354 if (!NILP (Vbinary_process_input))
355 flags |= _O_BINARY;
357 _pipe (fds, 0, flags);
358 inherit_in = dup (fds[0]);
359 close (fds[0]);
360 fds[0] = inherit_in;
363 /* The following two routines are used to manipulate stdin, stdout, and
364 stderr of our child processes.
366 Assuming that in, out, and err are inherited, we make them stdin,
367 stdout, and stderr of the child as follows:
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. */
379 void
380 prepare_standard_handles (int in, int out, int err, HANDLE handles[4])
382 HANDLE parent, stdin_save, stdout_save, stderr_save, err_handle;
384 parent = GetCurrentProcess ();
385 if (!DuplicateHandle (parent,
386 GetStdHandle (STD_INPUT_HANDLE),
387 parent,
388 &stdin_save,
390 FALSE,
391 DUPLICATE_SAME_ACCESS))
392 report_file_error ("Duplicating parent's input handle", Qnil);
394 if (!DuplicateHandle (parent,
395 GetStdHandle (STD_OUTPUT_HANDLE),
396 parent,
397 &stdout_save,
399 FALSE,
400 DUPLICATE_SAME_ACCESS))
401 report_file_error ("Duplicating parent's output handle", Qnil);
403 if (!DuplicateHandle (parent,
404 GetStdHandle (STD_ERROR_HANDLE),
405 parent,
406 &stderr_save,
408 FALSE,
409 DUPLICATE_SAME_ACCESS))
410 report_file_error ("Duplicating parent's error handle", Qnil);
412 if (!SetStdHandle (STD_INPUT_HANDLE, (HANDLE) _get_osfhandle (in)))
413 report_file_error ("Changing stdin handle", Qnil);
415 if (!SetStdHandle (STD_OUTPUT_HANDLE, (HANDLE) _get_osfhandle (out)))
416 report_file_error ("Changing stdout handle", Qnil);
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)
422 if (!DuplicateHandle (parent,
423 (HANDLE) _get_osfhandle (err),
424 parent,
425 &err_handle,
427 TRUE,
428 DUPLICATE_SAME_ACCESS))
429 report_file_error ("Duplicating out handle to make err handle.",
430 Qnil);
432 else
434 err_handle = (HANDLE) _get_osfhandle (err);
437 if (!SetStdHandle (STD_ERROR_HANDLE, err_handle))
438 report_file_error ("Changing stderr handle", Qnil);
440 handles[0] = stdin_save;
441 handles[1] = stdout_save;
442 handles[2] = stderr_save;
443 handles[3] = err_handle;
446 void
447 reset_standard_handles (int in, int out, int err, HANDLE handles[4])
449 HANDLE stdin_save = handles[0];
450 HANDLE stdout_save = handles[1];
451 HANDLE stderr_save = handles[2];
452 HANDLE err_handle = handles[3];
454 if (!SetStdHandle (STD_INPUT_HANDLE, stdin_save))
455 report_file_error ("Resetting input handle", Qnil);
457 if (!SetStdHandle (STD_OUTPUT_HANDLE, stdout_save))
458 report_file_error ("Resetting output handle", Qnil);
460 if (!SetStdHandle (STD_ERROR_HANDLE, stderr_save))
461 report_file_error ("Resetting error handle", Qnil);
463 if (out == err)
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);
473 /* Destructively turn backslashes into slashes. */
474 void
475 dostounix_filename (p)
476 register char *p;
478 while (*p)
480 if (*p == '\\')
481 *p = '/';
482 p++;
486 /* Routines that are no-ops on NT but are defined to get Emacs to compile. */
489 int
490 sigsetmask (int signal_mask)
492 return 0;
495 int
496 sigblock (int sig)
498 return 0;
501 int
502 kill (int pid, int signal)
504 return 0;
507 int
508 setpgrp (int pid, int gid)
510 return 0;
513 int
514 alarm (int seconds)
516 return 0;
519 int
520 unrequest_sigio (void)
522 return 0;
525 int
526 request_sigio (void)
528 return 0;
531 int
532 getuid ()
534 return 0;
537 int
538 geteuid ()
540 return 0;
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.) */
547 crlf_to_lf (n, buf)
548 register int n;
549 register unsigned char *buf;
551 unsigned char *np = buf;
552 unsigned char *startp = buf;
553 unsigned char *endp = buf + n;
555 if (n == 0)
556 return n;
557 while (buf < endp - 1)
559 if (*buf == 0x0d)
561 if (*(++buf) != 0x0a)
562 *np++ = 0x0d;
564 else
565 *np++ = *buf++;
567 if (buf < endp)
568 *np++ = *buf++;
569 return np - startp;
573 #ifdef PIGSFLY
574 Keep this around...we might need it later.
575 #ifdef WINDOWSNT
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.
582 char b[256], Name[256], RefD[256];
583 DWORD length = 256, rlength = 256, trash;
584 HANDLE Token;
585 SID_NAME_USE User;
587 if (1)
588 Vuser_real_name = build_string ("foo");
589 else if (!OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY, &Token))
591 Vuser_real_name = build_string ("unknown");
593 else if (!GetTokenInformation (Token, TokenUser, (PVOID)b, 256,
594 &trash))
596 CloseHandle (Token);
597 Vuser_real_name = build_string ("unknown");
599 else if (!LookupAccountSid ((void *)0, (PSID)b, Name, &length, RefD,
600 &rlength, &User))
602 CloseHandle (Token);
603 Vuser_real_name = build_string ("unknown");
605 else
606 Vuser_real_name = build_string (Name);
608 #else /* not WINDOWSNT */
609 #endif /* not WINDOWSNT */
610 #endif /* PIGSFLY */