* nt/dump.bat: Fix mixed EOLs.
[emacs.git] / src / w32.c
blobc10990bae3bcfcb1fed2484fe4b77509a4e1a49a
1 /* Utility and Unix shadow routines for GNU Emacs on the Microsoft W32 API.
2 Copyright (C) 1994, 1995, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
3 2007, 2008 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
21 Geoff Voelker (voelker@cs.washington.edu) 7-29-94
23 #include <stddef.h> /* for offsetof */
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <io.h>
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <ctype.h>
30 #include <signal.h>
31 #include <sys/file.h>
32 #include <sys/time.h>
33 #include <sys/utime.h>
34 #include <mbstring.h> /* for _mbspbrk */
36 /* must include CRT headers *before* config.h */
38 #ifdef HAVE_CONFIG_H
39 #include <config.h>
40 #endif
42 #undef access
43 #undef chdir
44 #undef chmod
45 #undef creat
46 #undef ctime
47 #undef fopen
48 #undef link
49 #undef mkdir
50 #undef mktemp
51 #undef open
52 #undef rename
53 #undef rmdir
54 #undef unlink
56 #undef close
57 #undef dup
58 #undef dup2
59 #undef pipe
60 #undef read
61 #undef write
63 #undef strerror
65 #include "lisp.h"
67 #include <pwd.h>
68 #include <grp.h>
70 #ifdef __GNUC__
71 #define _ANONYMOUS_UNION
72 #define _ANONYMOUS_STRUCT
73 #endif
74 #include <windows.h>
75 #include <lmcons.h>
76 #include <shlobj.h>
78 #ifdef HAVE_SOCKETS /* TCP connection support, if kernel can do it */
79 #include <sys/socket.h>
80 #undef socket
81 #undef bind
82 #undef connect
83 #undef htons
84 #undef ntohs
85 #undef inet_addr
86 #undef gethostname
87 #undef gethostbyname
88 #undef getservbyname
89 #undef getpeername
90 #undef shutdown
91 #undef setsockopt
92 #undef listen
93 #undef getsockname
94 #undef accept
95 #undef recvfrom
96 #undef sendto
97 #endif
99 #include "w32.h"
100 #include "ndir.h"
101 #include "w32heap.h"
102 #include "systime.h"
103 #include "dispextern.h" /* for xstrcasecmp */
105 /* For serial_configure and serial_open. */
106 #include "process.h"
107 /* From process.c */
108 extern Lisp_Object QCport, QCspeed, QCprocess;
109 extern Lisp_Object QCbytesize, QCstopbits, QCparity, Qodd, Qeven;
110 extern Lisp_Object QCflowcontrol, Qhw, Qsw, QCsummary;
112 typedef HRESULT (WINAPI * ShGetFolderPath_fn)
113 (IN HWND, IN int, IN HANDLE, IN DWORD, OUT char *);
115 void globals_of_w32 ();
116 static DWORD get_rid (PSID);
118 extern Lisp_Object Vw32_downcase_file_names;
119 extern Lisp_Object Vw32_generate_fake_inodes;
120 extern Lisp_Object Vw32_get_true_file_attributes;
121 /* Defined in process.c for its own purpose. */
122 extern Lisp_Object Qlocal;
124 extern int w32_num_mouse_buttons;
127 /* Initialization states.
129 WARNING: If you add any more such variables for additional APIs,
130 you MUST add initialization for them to globals_of_w32
131 below. This is because these variables might get set
132 to non-NULL values during dumping, but the dumped Emacs
133 cannot reuse those values, because it could be run on a
134 different version of the OS, where API addresses are
135 different. */
136 static BOOL g_b_init_is_windows_9x;
137 static BOOL g_b_init_open_process_token;
138 static BOOL g_b_init_get_token_information;
139 static BOOL g_b_init_lookup_account_sid;
140 static BOOL g_b_init_get_sid_identifier_authority;
141 static BOOL g_b_init_get_sid_sub_authority;
142 static BOOL g_b_init_get_sid_sub_authority_count;
143 static BOOL g_b_init_get_file_security;
144 static BOOL g_b_init_get_security_descriptor_owner;
145 static BOOL g_b_init_get_security_descriptor_group;
146 static BOOL g_b_init_is_valid_sid;
149 BEGIN: Wrapper functions around OpenProcessToken
150 and other functions in advapi32.dll that are only
151 supported in Windows NT / 2k / XP
153 /* ** Function pointer typedefs ** */
154 typedef BOOL (WINAPI * OpenProcessToken_Proc) (
155 HANDLE ProcessHandle,
156 DWORD DesiredAccess,
157 PHANDLE TokenHandle);
158 typedef BOOL (WINAPI * GetTokenInformation_Proc) (
159 HANDLE TokenHandle,
160 TOKEN_INFORMATION_CLASS TokenInformationClass,
161 LPVOID TokenInformation,
162 DWORD TokenInformationLength,
163 PDWORD ReturnLength);
164 typedef BOOL (WINAPI * GetProcessTimes_Proc) (
165 HANDLE process_handle,
166 LPFILETIME creation_time,
167 LPFILETIME exit_time,
168 LPFILETIME kernel_time,
169 LPFILETIME user_time);
171 GetProcessTimes_Proc get_process_times_fn = NULL;
173 #ifdef _UNICODE
174 const char * const LookupAccountSid_Name = "LookupAccountSidW";
175 const char * const GetFileSecurity_Name = "GetFileSecurityW";
176 #else
177 const char * const LookupAccountSid_Name = "LookupAccountSidA";
178 const char * const GetFileSecurity_Name = "GetFileSecurityA";
179 #endif
180 typedef BOOL (WINAPI * LookupAccountSid_Proc) (
181 LPCTSTR lpSystemName,
182 PSID Sid,
183 LPTSTR Name,
184 LPDWORD cbName,
185 LPTSTR DomainName,
186 LPDWORD cbDomainName,
187 PSID_NAME_USE peUse);
188 typedef PSID_IDENTIFIER_AUTHORITY (WINAPI * GetSidIdentifierAuthority_Proc) (
189 PSID pSid);
190 typedef PDWORD (WINAPI * GetSidSubAuthority_Proc) (
191 PSID pSid,
192 DWORD n);
193 typedef PUCHAR (WINAPI * GetSidSubAuthorityCount_Proc) (
194 PSID pSid);
195 typedef BOOL (WINAPI * GetFileSecurity_Proc) (
196 LPCTSTR lpFileName,
197 SECURITY_INFORMATION RequestedInformation,
198 PSECURITY_DESCRIPTOR pSecurityDescriptor,
199 DWORD nLength,
200 LPDWORD lpnLengthNeeded);
201 typedef BOOL (WINAPI * GetSecurityDescriptorOwner_Proc) (
202 PSECURITY_DESCRIPTOR pSecurityDescriptor,
203 PSID *pOwner,
204 LPBOOL lpbOwnerDefaulted);
205 typedef BOOL (WINAPI * GetSecurityDescriptorGroup_Proc) (
206 PSECURITY_DESCRIPTOR pSecurityDescriptor,
207 PSID *pGroup,
208 LPBOOL lpbGroupDefaulted);
209 typedef BOOL (WINAPI * IsValidSid_Proc) (
210 PSID sid);
212 /* ** A utility function ** */
213 static BOOL
214 is_windows_9x ()
216 static BOOL s_b_ret=0;
217 OSVERSIONINFO os_ver;
218 if (g_b_init_is_windows_9x == 0)
220 g_b_init_is_windows_9x = 1;
221 ZeroMemory(&os_ver, sizeof(OSVERSIONINFO));
222 os_ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
223 if (GetVersionEx (&os_ver))
225 s_b_ret = (os_ver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
228 return s_b_ret;
231 /* Get total user and system times for get-internal-run-time.
232 Returns a list of three integers if the times are provided by the OS
233 (NT derivatives), otherwise it returns the result of current-time. */
234 Lisp_Object
235 w32_get_internal_run_time ()
237 if (get_process_times_fn)
239 FILETIME create, exit, kernel, user;
240 HANDLE proc = GetCurrentProcess();
241 if ((*get_process_times_fn) (proc, &create, &exit, &kernel, &user))
243 LARGE_INTEGER user_int, kernel_int, total;
244 int microseconds;
245 user_int.LowPart = user.dwLowDateTime;
246 user_int.HighPart = user.dwHighDateTime;
247 kernel_int.LowPart = kernel.dwLowDateTime;
248 kernel_int.HighPart = kernel.dwHighDateTime;
249 total.QuadPart = user_int.QuadPart + kernel_int.QuadPart;
250 /* FILETIME is 100 nanosecond increments, Emacs only wants
251 microsecond resolution. */
252 total.QuadPart /= 10;
253 microseconds = total.QuadPart % 1000000;
254 total.QuadPart /= 1000000;
256 /* Sanity check to make sure we can represent the result. */
257 if (total.HighPart == 0)
259 int secs = total.LowPart;
261 return list3 (make_number ((secs >> 16) & 0xffff),
262 make_number (secs & 0xffff),
263 make_number (microseconds));
268 return Fcurrent_time ();
271 /* ** The wrapper functions ** */
273 BOOL WINAPI open_process_token (
274 HANDLE ProcessHandle,
275 DWORD DesiredAccess,
276 PHANDLE TokenHandle)
278 static OpenProcessToken_Proc s_pfn_Open_Process_Token = NULL;
279 HMODULE hm_advapi32 = NULL;
280 if (is_windows_9x () == TRUE)
282 return FALSE;
284 if (g_b_init_open_process_token == 0)
286 g_b_init_open_process_token = 1;
287 hm_advapi32 = LoadLibrary ("Advapi32.dll");
288 s_pfn_Open_Process_Token =
289 (OpenProcessToken_Proc) GetProcAddress (hm_advapi32, "OpenProcessToken");
291 if (s_pfn_Open_Process_Token == NULL)
293 return FALSE;
295 return (
296 s_pfn_Open_Process_Token (
297 ProcessHandle,
298 DesiredAccess,
299 TokenHandle)
303 BOOL WINAPI get_token_information (
304 HANDLE TokenHandle,
305 TOKEN_INFORMATION_CLASS TokenInformationClass,
306 LPVOID TokenInformation,
307 DWORD TokenInformationLength,
308 PDWORD ReturnLength)
310 static GetTokenInformation_Proc s_pfn_Get_Token_Information = NULL;
311 HMODULE hm_advapi32 = NULL;
312 if (is_windows_9x () == TRUE)
314 return FALSE;
316 if (g_b_init_get_token_information == 0)
318 g_b_init_get_token_information = 1;
319 hm_advapi32 = LoadLibrary ("Advapi32.dll");
320 s_pfn_Get_Token_Information =
321 (GetTokenInformation_Proc) GetProcAddress (hm_advapi32, "GetTokenInformation");
323 if (s_pfn_Get_Token_Information == NULL)
325 return FALSE;
327 return (
328 s_pfn_Get_Token_Information (
329 TokenHandle,
330 TokenInformationClass,
331 TokenInformation,
332 TokenInformationLength,
333 ReturnLength)
337 BOOL WINAPI lookup_account_sid (
338 LPCTSTR lpSystemName,
339 PSID Sid,
340 LPTSTR Name,
341 LPDWORD cbName,
342 LPTSTR DomainName,
343 LPDWORD cbDomainName,
344 PSID_NAME_USE peUse)
346 static LookupAccountSid_Proc s_pfn_Lookup_Account_Sid = NULL;
347 HMODULE hm_advapi32 = NULL;
348 if (is_windows_9x () == TRUE)
350 return FALSE;
352 if (g_b_init_lookup_account_sid == 0)
354 g_b_init_lookup_account_sid = 1;
355 hm_advapi32 = LoadLibrary ("Advapi32.dll");
356 s_pfn_Lookup_Account_Sid =
357 (LookupAccountSid_Proc) GetProcAddress (hm_advapi32, LookupAccountSid_Name);
359 if (s_pfn_Lookup_Account_Sid == NULL)
361 return FALSE;
363 return (
364 s_pfn_Lookup_Account_Sid (
365 lpSystemName,
366 Sid,
367 Name,
368 cbName,
369 DomainName,
370 cbDomainName,
371 peUse)
375 PSID_IDENTIFIER_AUTHORITY WINAPI get_sid_identifier_authority (
376 PSID pSid)
378 static GetSidIdentifierAuthority_Proc s_pfn_Get_Sid_Identifier_Authority = NULL;
379 HMODULE hm_advapi32 = NULL;
380 if (is_windows_9x () == TRUE)
382 return NULL;
384 if (g_b_init_get_sid_identifier_authority == 0)
386 g_b_init_get_sid_identifier_authority = 1;
387 hm_advapi32 = LoadLibrary ("Advapi32.dll");
388 s_pfn_Get_Sid_Identifier_Authority =
389 (GetSidIdentifierAuthority_Proc) GetProcAddress (
390 hm_advapi32, "GetSidIdentifierAuthority");
392 if (s_pfn_Get_Sid_Identifier_Authority == NULL)
394 return NULL;
396 return (s_pfn_Get_Sid_Identifier_Authority (pSid));
399 PDWORD WINAPI get_sid_sub_authority (
400 PSID pSid,
401 DWORD n)
403 static GetSidSubAuthority_Proc s_pfn_Get_Sid_Sub_Authority = NULL;
404 static DWORD zero = 0U;
405 HMODULE hm_advapi32 = NULL;
406 if (is_windows_9x () == TRUE)
408 return &zero;
410 if (g_b_init_get_sid_sub_authority == 0)
412 g_b_init_get_sid_sub_authority = 1;
413 hm_advapi32 = LoadLibrary ("Advapi32.dll");
414 s_pfn_Get_Sid_Sub_Authority =
415 (GetSidSubAuthority_Proc) GetProcAddress (
416 hm_advapi32, "GetSidSubAuthority");
418 if (s_pfn_Get_Sid_Sub_Authority == NULL)
420 return &zero;
422 return (s_pfn_Get_Sid_Sub_Authority (pSid, n));
425 PUCHAR WINAPI get_sid_sub_authority_count (
426 PSID pSid)
428 static GetSidSubAuthorityCount_Proc s_pfn_Get_Sid_Sub_Authority_Count = NULL;
429 static UCHAR zero = 0U;
430 HMODULE hm_advapi32 = NULL;
431 if (is_windows_9x () == TRUE)
433 return &zero;
435 if (g_b_init_get_sid_sub_authority_count == 0)
437 g_b_init_get_sid_sub_authority_count = 1;
438 hm_advapi32 = LoadLibrary ("Advapi32.dll");
439 s_pfn_Get_Sid_Sub_Authority_Count =
440 (GetSidSubAuthorityCount_Proc) GetProcAddress (
441 hm_advapi32, "GetSidSubAuthorityCount");
443 if (s_pfn_Get_Sid_Sub_Authority_Count == NULL)
445 return &zero;
447 return (s_pfn_Get_Sid_Sub_Authority_Count (pSid));
450 BOOL WINAPI get_file_security (
451 LPCTSTR lpFileName,
452 SECURITY_INFORMATION RequestedInformation,
453 PSECURITY_DESCRIPTOR pSecurityDescriptor,
454 DWORD nLength,
455 LPDWORD lpnLengthNeeded)
457 static GetFileSecurity_Proc s_pfn_Get_File_Security = NULL;
458 HMODULE hm_advapi32 = NULL;
459 if (is_windows_9x () == TRUE)
461 return FALSE;
463 if (g_b_init_get_file_security == 0)
465 g_b_init_get_file_security = 1;
466 hm_advapi32 = LoadLibrary ("Advapi32.dll");
467 s_pfn_Get_File_Security =
468 (GetFileSecurity_Proc) GetProcAddress (
469 hm_advapi32, GetFileSecurity_Name);
471 if (s_pfn_Get_File_Security == NULL)
473 return FALSE;
475 return (s_pfn_Get_File_Security (lpFileName, RequestedInformation,
476 pSecurityDescriptor, nLength,
477 lpnLengthNeeded));
480 BOOL WINAPI get_security_descriptor_owner (
481 PSECURITY_DESCRIPTOR pSecurityDescriptor,
482 PSID *pOwner,
483 LPBOOL lpbOwnerDefaulted)
485 static GetSecurityDescriptorOwner_Proc s_pfn_Get_Security_Descriptor_Owner = NULL;
486 HMODULE hm_advapi32 = NULL;
487 if (is_windows_9x () == TRUE)
489 return FALSE;
491 if (g_b_init_get_security_descriptor_owner == 0)
493 g_b_init_get_security_descriptor_owner = 1;
494 hm_advapi32 = LoadLibrary ("Advapi32.dll");
495 s_pfn_Get_Security_Descriptor_Owner =
496 (GetSecurityDescriptorOwner_Proc) GetProcAddress (
497 hm_advapi32, "GetSecurityDescriptorOwner");
499 if (s_pfn_Get_Security_Descriptor_Owner == NULL)
501 return FALSE;
503 return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor, pOwner,
504 lpbOwnerDefaulted));
507 BOOL WINAPI get_security_descriptor_group (
508 PSECURITY_DESCRIPTOR pSecurityDescriptor,
509 PSID *pGroup,
510 LPBOOL lpbGroupDefaulted)
512 static GetSecurityDescriptorGroup_Proc s_pfn_Get_Security_Descriptor_Group = NULL;
513 HMODULE hm_advapi32 = NULL;
514 if (is_windows_9x () == TRUE)
516 return FALSE;
518 if (g_b_init_get_security_descriptor_group == 0)
520 g_b_init_get_security_descriptor_group = 1;
521 hm_advapi32 = LoadLibrary ("Advapi32.dll");
522 s_pfn_Get_Security_Descriptor_Group =
523 (GetSecurityDescriptorGroup_Proc) GetProcAddress (
524 hm_advapi32, "GetSecurityDescriptorGroup");
526 if (s_pfn_Get_Security_Descriptor_Group == NULL)
528 return FALSE;
530 return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor, pGroup,
531 lpbGroupDefaulted));
534 BOOL WINAPI is_valid_sid (
535 PSID sid)
537 static IsValidSid_Proc s_pfn_Is_Valid_Sid = NULL;
538 HMODULE hm_advapi32 = NULL;
539 if (is_windows_9x () == TRUE)
541 return FALSE;
543 if (g_b_init_is_valid_sid == 0)
545 g_b_init_is_valid_sid = 1;
546 hm_advapi32 = LoadLibrary ("Advapi32.dll");
547 s_pfn_Is_Valid_Sid =
548 (IsValidSid_Proc) GetProcAddress (
549 hm_advapi32, "IsValidSid");
551 if (s_pfn_Is_Valid_Sid == NULL)
553 return FALSE;
555 return (s_pfn_Is_Valid_Sid (sid));
559 END: Wrapper functions around OpenProcessToken
560 and other functions in advapi32.dll that are only
561 supported in Windows NT / 2k / XP
565 /* Equivalent of strerror for W32 error codes. */
566 char *
567 w32_strerror (int error_no)
569 static char buf[500];
571 if (error_no == 0)
572 error_no = GetLastError ();
574 buf[0] = '\0';
575 if (!FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL,
576 error_no,
577 0, /* choose most suitable language */
578 buf, sizeof (buf), NULL))
579 sprintf (buf, "w32 error %u", error_no);
580 return buf;
583 /* Return 1 if P is a valid pointer to an object of size SIZE. Return
584 0 if P is NOT a valid pointer. Return -1 if we cannot validate P.
586 This is called from alloc.c:valid_pointer_p. */
588 w32_valid_pointer_p (void *p, int size)
590 SIZE_T done;
591 HANDLE h = OpenProcess (PROCESS_VM_READ, FALSE, GetCurrentProcessId ());
593 if (h)
595 unsigned char *buf = alloca (size);
596 int retval = ReadProcessMemory (h, p, buf, size, &done);
598 CloseHandle (h);
599 return retval;
601 else
602 return -1;
605 static char startup_dir[MAXPATHLEN];
607 /* Get the current working directory. */
608 char *
609 getwd (char *dir)
611 #if 0
612 if (GetCurrentDirectory (MAXPATHLEN, dir) > 0)
613 return dir;
614 return NULL;
615 #else
616 /* Emacs doesn't actually change directory itself, and we want to
617 force our real wd to be where emacs.exe is to avoid unnecessary
618 conflicts when trying to rename or delete directories. */
619 strcpy (dir, startup_dir);
620 return dir;
621 #endif
624 #ifndef HAVE_SOCKETS
625 /* Emulate gethostname. */
627 gethostname (char *buffer, int size)
629 /* NT only allows small host names, so the buffer is
630 certainly large enough. */
631 return !GetComputerName (buffer, &size);
633 #endif /* HAVE_SOCKETS */
635 /* Emulate getloadavg. */
637 getloadavg (double loadavg[], int nelem)
639 int i;
641 /* A faithful emulation is going to have to be saved for a rainy day. */
642 for (i = 0; i < nelem; i++)
644 loadavg[i] = 0.0;
646 return i;
649 /* Emulate getpwuid, getpwnam and others. */
651 #define PASSWD_FIELD_SIZE 256
653 static char dflt_passwd_name[PASSWD_FIELD_SIZE];
654 static char dflt_passwd_passwd[PASSWD_FIELD_SIZE];
655 static char dflt_passwd_gecos[PASSWD_FIELD_SIZE];
656 static char dflt_passwd_dir[PASSWD_FIELD_SIZE];
657 static char dflt_passwd_shell[PASSWD_FIELD_SIZE];
659 static struct passwd dflt_passwd =
661 dflt_passwd_name,
662 dflt_passwd_passwd,
666 dflt_passwd_gecos,
667 dflt_passwd_dir,
668 dflt_passwd_shell,
671 static char dflt_group_name[GNLEN+1];
673 static struct group dflt_group =
675 /* When group information is not available, we return this as the
676 group for all files. */
677 dflt_group_name,
682 getuid ()
684 return dflt_passwd.pw_uid;
688 geteuid ()
690 /* I could imagine arguing for checking to see whether the user is
691 in the Administrators group and returning a UID of 0 for that
692 case, but I don't know how wise that would be in the long run. */
693 return getuid ();
697 getgid ()
699 return dflt_passwd.pw_gid;
703 getegid ()
705 return getgid ();
708 struct passwd *
709 getpwuid (int uid)
711 if (uid == dflt_passwd.pw_uid)
712 return &dflt_passwd;
713 return NULL;
716 struct group *
717 getgrgid (gid_t gid)
719 return &dflt_group;
722 struct passwd *
723 getpwnam (char *name)
725 struct passwd *pw;
727 pw = getpwuid (getuid ());
728 if (!pw)
729 return pw;
731 if (xstrcasecmp (name, pw->pw_name))
732 return NULL;
734 return pw;
737 void
738 init_user_info ()
740 /* Find the user's real name by opening the process token and
741 looking up the name associated with the user-sid in that token.
743 Use the relative portion of the identifier authority value from
744 the user-sid as the user id value (same for group id using the
745 primary group sid from the process token). */
747 char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
748 DWORD ulength = sizeof (uname), dlength = sizeof (domain), trash;
749 DWORD glength = sizeof (gname);
750 HANDLE token = NULL;
751 SID_NAME_USE user_type;
752 unsigned char buf[1024];
753 TOKEN_USER user_token;
754 TOKEN_PRIMARY_GROUP group_token;
756 if (open_process_token (GetCurrentProcess (), TOKEN_QUERY, &token)
757 && get_token_information (token, TokenUser,
758 (PVOID)buf, sizeof (buf), &trash)
759 && (memcpy (&user_token, buf, sizeof (user_token)),
760 lookup_account_sid (NULL, user_token.User.Sid, uname, &ulength,
761 domain, &dlength, &user_type)))
763 strcpy (dflt_passwd.pw_name, uname);
764 /* Determine a reasonable uid value. */
765 if (xstrcasecmp ("administrator", uname) == 0)
767 dflt_passwd.pw_uid = 500; /* well-known Administrator uid */
768 dflt_passwd.pw_gid = 513; /* well-known None gid */
770 else
772 /* Use the last sub-authority value of the RID, the relative
773 portion of the SID, as user/group ID. */
774 dflt_passwd.pw_uid = get_rid (user_token.User.Sid);
776 /* Get group id and name. */
777 if (get_token_information (token, TokenPrimaryGroup,
778 (PVOID)buf, sizeof (buf), &trash))
780 memcpy (&group_token, buf, sizeof (group_token));
781 dflt_passwd.pw_gid = get_rid (group_token.PrimaryGroup);
782 dlength = sizeof (domain);
783 if (lookup_account_sid (NULL, group_token.PrimaryGroup,
784 gname, &glength, NULL, &dlength,
785 &user_type))
786 strcpy (dflt_group_name, gname);
788 else
789 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
792 /* If security calls are not supported (presumably because we
793 are running under Windows 95), fallback to this. */
794 else if (GetUserName (uname, &ulength))
796 strcpy (dflt_passwd.pw_name, uname);
797 if (xstrcasecmp ("administrator", uname) == 0)
798 dflt_passwd.pw_uid = 0;
799 else
800 dflt_passwd.pw_uid = 123;
801 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
803 else
805 strcpy (dflt_passwd.pw_name, "unknown");
806 dflt_passwd.pw_uid = 123;
807 dflt_passwd.pw_gid = 123;
809 dflt_group.gr_gid = dflt_passwd.pw_gid;
811 /* Ensure HOME and SHELL are defined. */
812 if (getenv ("HOME") == NULL)
813 abort ();
814 if (getenv ("SHELL") == NULL)
815 abort ();
817 /* Set dir and shell from environment variables. */
818 strcpy (dflt_passwd.pw_dir, getenv ("HOME"));
819 strcpy (dflt_passwd.pw_shell, getenv ("SHELL"));
821 if (token)
822 CloseHandle (token);
826 random ()
828 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
829 return ((rand () << 15) | rand ());
832 void
833 srandom (int seed)
835 srand (seed);
839 /* Normalize filename by converting all path separators to
840 the specified separator. Also conditionally convert upper
841 case path name components to lower case. */
843 static void
844 normalize_filename (fp, path_sep)
845 register char *fp;
846 char path_sep;
848 char sep;
849 char *elem;
851 /* Always lower-case drive letters a-z, even if the filesystem
852 preserves case in filenames.
853 This is so filenames can be compared by string comparison
854 functions that are case-sensitive. Even case-preserving filesystems
855 do not distinguish case in drive letters. */
856 if (fp[1] == ':' && *fp >= 'A' && *fp <= 'Z')
858 *fp += 'a' - 'A';
859 fp += 2;
862 if (NILP (Vw32_downcase_file_names))
864 while (*fp)
866 if (*fp == '/' || *fp == '\\')
867 *fp = path_sep;
868 fp++;
870 return;
873 sep = path_sep; /* convert to this path separator */
874 elem = fp; /* start of current path element */
876 do {
877 if (*fp >= 'a' && *fp <= 'z')
878 elem = 0; /* don't convert this element */
880 if (*fp == 0 || *fp == ':')
882 sep = *fp; /* restore current separator (or 0) */
883 *fp = '/'; /* after conversion of this element */
886 if (*fp == '/' || *fp == '\\')
888 if (elem && elem != fp)
890 *fp = 0; /* temporary end of string */
891 _strlwr (elem); /* while we convert to lower case */
893 *fp = sep; /* convert (or restore) path separator */
894 elem = fp + 1; /* next element starts after separator */
895 sep = path_sep;
897 } while (*fp++);
900 /* Destructively turn backslashes into slashes. */
901 void
902 dostounix_filename (p)
903 register char *p;
905 normalize_filename (p, '/');
908 /* Destructively turn slashes into backslashes. */
909 void
910 unixtodos_filename (p)
911 register char *p;
913 normalize_filename (p, '\\');
916 /* Remove all CR's that are followed by a LF.
917 (From msdos.c...probably should figure out a way to share it,
918 although this code isn't going to ever change.) */
920 crlf_to_lf (n, buf)
921 register int n;
922 register unsigned char *buf;
924 unsigned char *np = buf;
925 unsigned char *startp = buf;
926 unsigned char *endp = buf + n;
928 if (n == 0)
929 return n;
930 while (buf < endp - 1)
932 if (*buf == 0x0d)
934 if (*(++buf) != 0x0a)
935 *np++ = 0x0d;
937 else
938 *np++ = *buf++;
940 if (buf < endp)
941 *np++ = *buf++;
942 return np - startp;
945 /* Parse the root part of file name, if present. Return length and
946 optionally store pointer to char after root. */
947 static int
948 parse_root (char * name, char ** pPath)
950 char * start = name;
952 if (name == NULL)
953 return 0;
955 /* find the root name of the volume if given */
956 if (isalpha (name[0]) && name[1] == ':')
958 /* skip past drive specifier */
959 name += 2;
960 if (IS_DIRECTORY_SEP (name[0]))
961 name++;
963 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
965 int slashes = 2;
966 name += 2;
969 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
970 break;
971 name++;
973 while ( *name );
974 if (IS_DIRECTORY_SEP (name[0]))
975 name++;
978 if (pPath)
979 *pPath = name;
981 return name - start;
984 /* Get long base name for name; name is assumed to be absolute. */
985 static int
986 get_long_basename (char * name, char * buf, int size)
988 WIN32_FIND_DATA find_data;
989 HANDLE dir_handle;
990 int len = 0;
992 /* must be valid filename, no wild cards or other invalid characters */
993 if (_mbspbrk (name, "*?|<>\""))
994 return 0;
996 dir_handle = FindFirstFile (name, &find_data);
997 if (dir_handle != INVALID_HANDLE_VALUE)
999 if ((len = strlen (find_data.cFileName)) < size)
1000 memcpy (buf, find_data.cFileName, len + 1);
1001 else
1002 len = 0;
1003 FindClose (dir_handle);
1005 return len;
1008 /* Get long name for file, if possible (assumed to be absolute). */
1009 BOOL
1010 w32_get_long_filename (char * name, char * buf, int size)
1012 char * o = buf;
1013 char * p;
1014 char * q;
1015 char full[ MAX_PATH ];
1016 int len;
1018 len = strlen (name);
1019 if (len >= MAX_PATH)
1020 return FALSE;
1022 /* Use local copy for destructive modification. */
1023 memcpy (full, name, len+1);
1024 unixtodos_filename (full);
1026 /* Copy root part verbatim. */
1027 len = parse_root (full, &p);
1028 memcpy (o, full, len);
1029 o += len;
1030 *o = '\0';
1031 size -= len;
1033 while (p != NULL && *p)
1035 q = p;
1036 p = strchr (q, '\\');
1037 if (p) *p = '\0';
1038 len = get_long_basename (full, o, size);
1039 if (len > 0)
1041 o += len;
1042 size -= len;
1043 if (p != NULL)
1045 *p++ = '\\';
1046 if (size < 2)
1047 return FALSE;
1048 *o++ = '\\';
1049 size--;
1050 *o = '\0';
1053 else
1054 return FALSE;
1057 return TRUE;
1061 is_unc_volume (const char *filename)
1063 const char *ptr = filename;
1065 if (!IS_DIRECTORY_SEP (ptr[0]) || !IS_DIRECTORY_SEP (ptr[1]) || !ptr[2])
1066 return 0;
1068 if (_mbspbrk (ptr + 2, "*?|<>\"\\/"))
1069 return 0;
1071 return 1;
1074 /* Routines that are no-ops on NT but are defined to get Emacs to compile. */
1077 sigsetmask (int signal_mask)
1079 return 0;
1083 sigmask (int sig)
1085 return 0;
1089 sigblock (int sig)
1091 return 0;
1095 sigunblock (int sig)
1097 return 0;
1101 setpgrp (int pid, int gid)
1103 return 0;
1107 alarm (int seconds)
1109 return 0;
1112 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
1114 LPBYTE
1115 w32_get_resource (key, lpdwtype)
1116 char *key;
1117 LPDWORD lpdwtype;
1119 LPBYTE lpvalue;
1120 HKEY hrootkey = NULL;
1121 DWORD cbData;
1123 /* Check both the current user and the local machine to see if
1124 we have any resources. */
1126 if (RegOpenKeyEx (HKEY_CURRENT_USER, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
1128 lpvalue = NULL;
1130 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
1131 && (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL
1132 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
1134 RegCloseKey (hrootkey);
1135 return (lpvalue);
1138 xfree (lpvalue);
1140 RegCloseKey (hrootkey);
1143 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
1145 lpvalue = NULL;
1147 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
1148 && (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL
1149 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
1151 RegCloseKey (hrootkey);
1152 return (lpvalue);
1155 xfree (lpvalue);
1157 RegCloseKey (hrootkey);
1160 return (NULL);
1163 char *get_emacs_configuration (void);
1164 extern Lisp_Object Vsystem_configuration;
1166 void
1167 init_environment (char ** argv)
1169 static const char * const tempdirs[] = {
1170 "$TMPDIR", "$TEMP", "$TMP", "c:/"
1173 int i;
1175 const int imax = sizeof (tempdirs) / sizeof (tempdirs[0]);
1177 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
1178 temporary files and assume "/tmp" if $TMPDIR is unset, which
1179 will break on DOS/Windows. Refuse to work if we cannot find
1180 a directory, not even "c:/", usable for that purpose. */
1181 for (i = 0; i < imax ; i++)
1183 const char *tmp = tempdirs[i];
1185 if (*tmp == '$')
1186 tmp = getenv (tmp + 1);
1187 /* Note that `access' can lie to us if the directory resides on a
1188 read-only filesystem, like CD-ROM or a write-protected floppy.
1189 The only way to be really sure is to actually create a file and
1190 see if it succeeds. But I think that's too much to ask. */
1191 if (tmp && _access (tmp, D_OK) == 0)
1193 char * var = alloca (strlen (tmp) + 8);
1194 sprintf (var, "TMPDIR=%s", tmp);
1195 _putenv (strdup (var));
1196 break;
1199 if (i >= imax)
1200 cmd_error_internal
1201 (Fcons (Qerror,
1202 Fcons (build_string ("no usable temporary directories found!!"),
1203 Qnil)),
1204 "While setting TMPDIR: ");
1206 /* Check for environment variables and use registry settings if they
1207 don't exist. Fallback on default values where applicable. */
1209 int i;
1210 LPBYTE lpval;
1211 DWORD dwType;
1212 char locale_name[32];
1213 struct stat ignored;
1214 char default_home[MAX_PATH];
1216 static const struct env_entry
1218 char * name;
1219 char * def_value;
1220 } dflt_envvars[] =
1222 {"HOME", "C:/"},
1223 {"PRELOAD_WINSOCK", NULL},
1224 {"emacs_dir", "C:/emacs"},
1225 {"EMACSLOADPATH", "%emacs_dir%/site-lisp;%emacs_dir%/../site-lisp;%emacs_dir%/lisp;%emacs_dir%/leim"},
1226 {"SHELL", "%emacs_dir%/bin/cmdproxy.exe"},
1227 {"EMACSDATA", "%emacs_dir%/etc"},
1228 {"EMACSPATH", "%emacs_dir%/bin"},
1229 /* We no longer set INFOPATH because Info-default-directory-list
1230 is then ignored. */
1231 /* {"INFOPATH", "%emacs_dir%/info"}, */
1232 {"EMACSDOC", "%emacs_dir%/etc"},
1233 {"TERM", "cmd"},
1234 {"LANG", NULL},
1237 #define N_ENV_VARS sizeof(dflt_envvars)/sizeof(dflt_envvars[0])
1239 /* We need to copy dflt_envvars[] and work on the copy because we
1240 don't want the dumped Emacs to inherit the values of
1241 environment variables we saw during dumping (which could be on
1242 a different system). The defaults above must be left intact. */
1243 struct env_entry env_vars[N_ENV_VARS];
1245 for (i = 0; i < N_ENV_VARS; i++)
1246 env_vars[i] = dflt_envvars[i];
1248 /* For backwards compatibility, check if a .emacs file exists in C:/
1249 If not, then we can try to default to the appdata directory under the
1250 user's profile, which is more likely to be writable. */
1251 if (stat ("C:/.emacs", &ignored) < 0)
1253 HRESULT profile_result;
1254 /* Dynamically load ShGetFolderPath, as it won't exist on versions
1255 of Windows 95 and NT4 that have not been updated to include
1256 MSIE 5. Also we don't link with shell32.dll by default. */
1257 HMODULE shell32_dll;
1258 ShGetFolderPath_fn get_folder_path;
1259 shell32_dll = GetModuleHandle ("shell32.dll");
1260 get_folder_path = (ShGetFolderPath_fn)
1261 GetProcAddress (shell32_dll, "SHGetFolderPathA");
1263 if (get_folder_path != NULL)
1265 profile_result = get_folder_path (NULL, CSIDL_APPDATA, NULL,
1266 0, default_home);
1268 /* If we can't get the appdata dir, revert to old behavior. */
1269 if (profile_result == S_OK)
1270 env_vars[0].def_value = default_home;
1273 /* Unload shell32.dll, it is not needed anymore. */
1274 FreeLibrary (shell32_dll);
1277 /* Get default locale info and use it for LANG. */
1278 if (GetLocaleInfo (LOCALE_USER_DEFAULT,
1279 LOCALE_SABBREVLANGNAME | LOCALE_USE_CP_ACP,
1280 locale_name, sizeof (locale_name)))
1282 for (i = 0; i < N_ENV_VARS; i++)
1284 if (strcmp (env_vars[i].name, "LANG") == 0)
1286 env_vars[i].def_value = locale_name;
1287 break;
1292 #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
1294 /* Treat emacs_dir specially: set it unconditionally based on our
1295 location, if it appears that we are running from the bin subdir
1296 of a standard installation. */
1298 char *p;
1299 char modname[MAX_PATH];
1301 if (!GetModuleFileName (NULL, modname, MAX_PATH))
1302 abort ();
1303 if ((p = strrchr (modname, '\\')) == NULL)
1304 abort ();
1305 *p = 0;
1307 if ((p = strrchr (modname, '\\')) && xstrcasecmp (p, "\\bin") == 0)
1309 char buf[SET_ENV_BUF_SIZE];
1311 *p = 0;
1312 for (p = modname; *p; p++)
1313 if (*p == '\\') *p = '/';
1315 _snprintf (buf, sizeof(buf)-1, "emacs_dir=%s", modname);
1316 _putenv (strdup (buf));
1318 /* Handle running emacs from the build directory: src/oo-spd/i386/ */
1320 /* FIXME: should use substring of get_emacs_configuration ().
1321 But I don't think the Windows build supports alpha, mips etc
1322 anymore, so have taken the easy option for now. */
1323 else if (p && xstrcasecmp (p, "\\i386") == 0)
1325 *p = 0;
1326 p = strrchr (modname, '\\');
1327 if (p != NULL)
1329 *p = 0;
1330 p = strrchr (modname, '\\');
1331 if (p && xstrcasecmp (p, "\\src") == 0)
1333 char buf[SET_ENV_BUF_SIZE];
1335 *p = 0;
1336 for (p = modname; *p; p++)
1337 if (*p == '\\') *p = '/';
1339 _snprintf (buf, sizeof(buf)-1, "emacs_dir=%s", modname);
1340 _putenv (strdup (buf));
1346 for (i = 0; i < N_ENV_VARS; i++)
1348 if (!getenv (env_vars[i].name))
1350 int dont_free = 0;
1352 if ((lpval = w32_get_resource (env_vars[i].name, &dwType)) == NULL
1353 /* Also ignore empty environment variables. */
1354 || *lpval == 0)
1356 xfree (lpval);
1357 lpval = env_vars[i].def_value;
1358 dwType = REG_EXPAND_SZ;
1359 dont_free = 1;
1362 if (lpval)
1364 char buf1[SET_ENV_BUF_SIZE], buf2[SET_ENV_BUF_SIZE];
1366 if (dwType == REG_EXPAND_SZ)
1367 ExpandEnvironmentStrings ((LPSTR) lpval, buf1, sizeof(buf1));
1368 else if (dwType == REG_SZ)
1369 strcpy (buf1, lpval);
1370 if (dwType == REG_EXPAND_SZ || dwType == REG_SZ)
1372 _snprintf (buf2, sizeof(buf2)-1, "%s=%s", env_vars[i].name,
1373 buf1);
1374 _putenv (strdup (buf2));
1377 if (!dont_free)
1378 xfree (lpval);
1384 /* Rebuild system configuration to reflect invoking system. */
1385 Vsystem_configuration = build_string (EMACS_CONFIGURATION);
1387 /* Another special case: on NT, the PATH variable is actually named
1388 "Path" although cmd.exe (perhaps NT itself) arranges for
1389 environment variable lookup and setting to be case insensitive.
1390 However, Emacs assumes a fully case sensitive environment, so we
1391 need to change "Path" to "PATH" to match the expectations of
1392 various elisp packages. We do this by the sneaky method of
1393 modifying the string in the C runtime environ entry.
1395 The same applies to COMSPEC. */
1397 char ** envp;
1399 for (envp = environ; *envp; envp++)
1400 if (_strnicmp (*envp, "PATH=", 5) == 0)
1401 memcpy (*envp, "PATH=", 5);
1402 else if (_strnicmp (*envp, "COMSPEC=", 8) == 0)
1403 memcpy (*envp, "COMSPEC=", 8);
1406 /* Remember the initial working directory for getwd, then make the
1407 real wd be the location of emacs.exe to avoid conflicts when
1408 renaming or deleting directories. (We also don't call chdir when
1409 running subprocesses for the same reason.) */
1410 if (!GetCurrentDirectory (MAXPATHLEN, startup_dir))
1411 abort ();
1414 char *p;
1415 static char modname[MAX_PATH];
1417 if (!GetModuleFileName (NULL, modname, MAX_PATH))
1418 abort ();
1419 if ((p = strrchr (modname, '\\')) == NULL)
1420 abort ();
1421 *p = 0;
1423 SetCurrentDirectory (modname);
1425 /* Ensure argv[0] has the full path to Emacs. */
1426 *p = '\\';
1427 argv[0] = modname;
1430 /* Determine if there is a middle mouse button, to allow parse_button
1431 to decide whether right mouse events should be mouse-2 or
1432 mouse-3. */
1433 w32_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);
1435 init_user_info ();
1438 char *
1439 emacs_root_dir (void)
1441 static char root_dir[FILENAME_MAX];
1442 const char *p;
1444 p = getenv ("emacs_dir");
1445 if (p == NULL)
1446 abort ();
1447 strcpy (root_dir, p);
1448 root_dir[parse_root (root_dir, NULL)] = '\0';
1449 dostounix_filename (root_dir);
1450 return root_dir;
1453 /* We don't have scripts to automatically determine the system configuration
1454 for Emacs before it's compiled, and we don't want to have to make the
1455 user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
1456 routine. */
1458 char *
1459 get_emacs_configuration (void)
1461 char *arch, *oem, *os;
1462 int build_num;
1463 static char configuration_buffer[32];
1465 /* Determine the processor type. */
1466 switch (get_processor_type ())
1469 #ifdef PROCESSOR_INTEL_386
1470 case PROCESSOR_INTEL_386:
1471 case PROCESSOR_INTEL_486:
1472 case PROCESSOR_INTEL_PENTIUM:
1473 arch = "i386";
1474 break;
1475 #endif
1477 #ifdef PROCESSOR_MIPS_R2000
1478 case PROCESSOR_MIPS_R2000:
1479 case PROCESSOR_MIPS_R3000:
1480 case PROCESSOR_MIPS_R4000:
1481 arch = "mips";
1482 break;
1483 #endif
1485 #ifdef PROCESSOR_ALPHA_21064
1486 case PROCESSOR_ALPHA_21064:
1487 arch = "alpha";
1488 break;
1489 #endif
1491 default:
1492 arch = "unknown";
1493 break;
1496 /* Use the OEM field to reflect the compiler/library combination. */
1497 #ifdef _MSC_VER
1498 #define COMPILER_NAME "msvc"
1499 #else
1500 #ifdef __GNUC__
1501 #define COMPILER_NAME "mingw"
1502 #else
1503 #define COMPILER_NAME "unknown"
1504 #endif
1505 #endif
1506 oem = COMPILER_NAME;
1508 switch (osinfo_cache.dwPlatformId) {
1509 case VER_PLATFORM_WIN32_NT:
1510 os = "nt";
1511 build_num = osinfo_cache.dwBuildNumber;
1512 break;
1513 case VER_PLATFORM_WIN32_WINDOWS:
1514 if (osinfo_cache.dwMinorVersion == 0) {
1515 os = "windows95";
1516 } else {
1517 os = "windows98";
1519 build_num = LOWORD (osinfo_cache.dwBuildNumber);
1520 break;
1521 case VER_PLATFORM_WIN32s:
1522 /* Not supported, should not happen. */
1523 os = "windows32s";
1524 build_num = LOWORD (osinfo_cache.dwBuildNumber);
1525 break;
1526 default:
1527 os = "unknown";
1528 build_num = 0;
1529 break;
1532 if (osinfo_cache.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1533 sprintf (configuration_buffer, "%s-%s-%s%d.%d.%d", arch, oem, os,
1534 get_w32_major_version (), get_w32_minor_version (), build_num);
1535 } else {
1536 sprintf (configuration_buffer, "%s-%s-%s.%d", arch, oem, os, build_num);
1539 return configuration_buffer;
1542 char *
1543 get_emacs_configuration_options (void)
1545 static char options_buffer[256];
1547 /* Work out the effective configure options for this build. */
1548 #ifdef _MSC_VER
1549 #define COMPILER_VERSION "--with-msvc (%d.%02d)", _MSC_VER / 100, _MSC_VER % 100
1550 #else
1551 #ifdef __GNUC__
1552 #define COMPILER_VERSION "--with-gcc (%d.%d)", __GNUC__, __GNUC_MINOR__
1553 #else
1554 #define COMPILER_VERSION ""
1555 #endif
1556 #endif
1558 sprintf (options_buffer, COMPILER_VERSION);
1559 #ifdef EMACSDEBUG
1560 strcat (options_buffer, " --no-opt");
1561 #endif
1562 #ifdef USER_CFLAGS
1563 strcat (options_buffer, " --cflags");
1564 strcat (options_buffer, USER_CFLAGS);
1565 #endif
1566 #ifdef USER_LDFLAGS
1567 strcat (options_buffer, " --ldflags");
1568 strcat (options_buffer, USER_LDFLAGS);
1569 #endif
1570 return options_buffer;
1574 #include <sys/timeb.h>
1576 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
1577 void
1578 gettimeofday (struct timeval *tv, struct timezone *tz)
1580 struct _timeb tb;
1581 _ftime (&tb);
1583 tv->tv_sec = tb.time;
1584 tv->tv_usec = tb.millitm * 1000L;
1585 if (tz)
1587 tz->tz_minuteswest = tb.timezone; /* minutes west of Greenwich */
1588 tz->tz_dsttime = tb.dstflag; /* type of dst correction */
1592 /* ------------------------------------------------------------------------- */
1593 /* IO support and wrapper functions for W32 API. */
1594 /* ------------------------------------------------------------------------- */
1596 /* Place a wrapper around the MSVC version of ctime. It returns NULL
1597 on network directories, so we handle that case here.
1598 (Ulrich Leodolter, 1/11/95). */
1599 char *
1600 sys_ctime (const time_t *t)
1602 char *str = (char *) ctime (t);
1603 return (str ? str : "Sun Jan 01 00:00:00 1970");
1606 /* Emulate sleep...we could have done this with a define, but that
1607 would necessitate including windows.h in the files that used it.
1608 This is much easier. */
1609 void
1610 sys_sleep (int seconds)
1612 Sleep (seconds * 1000);
1615 /* Internal MSVC functions for low-level descriptor munging */
1616 extern int __cdecl _set_osfhnd (int fd, long h);
1617 extern int __cdecl _free_osfhnd (int fd);
1619 /* parallel array of private info on file handles */
1620 filedesc fd_info [ MAXDESC ];
1622 typedef struct volume_info_data {
1623 struct volume_info_data * next;
1625 /* time when info was obtained */
1626 DWORD timestamp;
1628 /* actual volume info */
1629 char * root_dir;
1630 DWORD serialnum;
1631 DWORD maxcomp;
1632 DWORD flags;
1633 char * name;
1634 char * type;
1635 } volume_info_data;
1637 /* Global referenced by various functions. */
1638 static volume_info_data volume_info;
1640 /* Vector to indicate which drives are local and fixed (for which cached
1641 data never expires). */
1642 static BOOL fixed_drives[26];
1644 /* Consider cached volume information to be stale if older than 10s,
1645 at least for non-local drives. Info for fixed drives is never stale. */
1646 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
1647 #define VOLINFO_STILL_VALID( root_dir, info ) \
1648 ( ( isalpha (root_dir[0]) && \
1649 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
1650 || GetTickCount () - info->timestamp < 10000 )
1652 /* Cache support functions. */
1654 /* Simple linked list with linear search is sufficient. */
1655 static volume_info_data *volume_cache = NULL;
1657 static volume_info_data *
1658 lookup_volume_info (char * root_dir)
1660 volume_info_data * info;
1662 for (info = volume_cache; info; info = info->next)
1663 if (xstrcasecmp (info->root_dir, root_dir) == 0)
1664 break;
1665 return info;
1668 static void
1669 add_volume_info (char * root_dir, volume_info_data * info)
1671 info->root_dir = xstrdup (root_dir);
1672 info->next = volume_cache;
1673 volume_cache = info;
1677 /* Wrapper for GetVolumeInformation, which uses caching to avoid
1678 performance penalty (~2ms on 486 for local drives, 7.5ms for local
1679 cdrom drive, ~5-10ms or more for remote drives on LAN). */
1680 volume_info_data *
1681 GetCachedVolumeInformation (char * root_dir)
1683 volume_info_data * info;
1684 char default_root[ MAX_PATH ];
1686 /* NULL for root_dir means use root from current directory. */
1687 if (root_dir == NULL)
1689 if (GetCurrentDirectory (MAX_PATH, default_root) == 0)
1690 return NULL;
1691 parse_root (default_root, &root_dir);
1692 *root_dir = 0;
1693 root_dir = default_root;
1696 /* Local fixed drives can be cached permanently. Removable drives
1697 cannot be cached permanently, since the volume name and serial
1698 number (if nothing else) can change. Remote drives should be
1699 treated as if they are removable, since there is no sure way to
1700 tell whether they are or not. Also, the UNC association of drive
1701 letters mapped to remote volumes can be changed at any time (even
1702 by other processes) without notice.
1704 As a compromise, so we can benefit from caching info for remote
1705 volumes, we use a simple expiry mechanism to invalidate cache
1706 entries that are more than ten seconds old. */
1708 #if 0
1709 /* No point doing this, because WNetGetConnection is even slower than
1710 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
1711 GetDriveType is about the only call of this type which does not
1712 involve network access, and so is extremely quick). */
1714 /* Map drive letter to UNC if remote. */
1715 if ( isalpha( root_dir[0] ) && !fixed[ DRIVE_INDEX( root_dir[0] ) ] )
1717 char remote_name[ 256 ];
1718 char drive[3] = { root_dir[0], ':' };
1720 if (WNetGetConnection (drive, remote_name, sizeof (remote_name))
1721 == NO_ERROR)
1722 /* do something */ ;
1724 #endif
1726 info = lookup_volume_info (root_dir);
1728 if (info == NULL || ! VOLINFO_STILL_VALID (root_dir, info))
1730 char name[ 256 ];
1731 DWORD serialnum;
1732 DWORD maxcomp;
1733 DWORD flags;
1734 char type[ 256 ];
1736 /* Info is not cached, or is stale. */
1737 if (!GetVolumeInformation (root_dir,
1738 name, sizeof (name),
1739 &serialnum,
1740 &maxcomp,
1741 &flags,
1742 type, sizeof (type)))
1743 return NULL;
1745 /* Cache the volume information for future use, overwriting existing
1746 entry if present. */
1747 if (info == NULL)
1749 info = (volume_info_data *) xmalloc (sizeof (volume_info_data));
1750 add_volume_info (root_dir, info);
1752 else
1754 xfree (info->name);
1755 xfree (info->type);
1758 info->name = xstrdup (name);
1759 info->serialnum = serialnum;
1760 info->maxcomp = maxcomp;
1761 info->flags = flags;
1762 info->type = xstrdup (type);
1763 info->timestamp = GetTickCount ();
1766 return info;
1769 /* Get information on the volume where name is held; set path pointer to
1770 start of pathname in name (past UNC header\volume header if present). */
1772 get_volume_info (const char * name, const char ** pPath)
1774 char temp[MAX_PATH];
1775 char *rootname = NULL; /* default to current volume */
1776 volume_info_data * info;
1778 if (name == NULL)
1779 return FALSE;
1781 /* find the root name of the volume if given */
1782 if (isalpha (name[0]) && name[1] == ':')
1784 rootname = temp;
1785 temp[0] = *name++;
1786 temp[1] = *name++;
1787 temp[2] = '\\';
1788 temp[3] = 0;
1790 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
1792 char *str = temp;
1793 int slashes = 4;
1794 rootname = temp;
1797 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
1798 break;
1799 *str++ = *name++;
1801 while ( *name );
1803 *str++ = '\\';
1804 *str = 0;
1807 if (pPath)
1808 *pPath = name;
1810 info = GetCachedVolumeInformation (rootname);
1811 if (info != NULL)
1813 /* Set global referenced by other functions. */
1814 volume_info = *info;
1815 return TRUE;
1817 return FALSE;
1820 /* Determine if volume is FAT format (ie. only supports short 8.3
1821 names); also set path pointer to start of pathname in name. */
1823 is_fat_volume (const char * name, const char ** pPath)
1825 if (get_volume_info (name, pPath))
1826 return (volume_info.maxcomp == 12);
1827 return FALSE;
1830 /* Map filename to a valid 8.3 name if necessary. */
1831 const char *
1832 map_w32_filename (const char * name, const char ** pPath)
1834 static char shortname[MAX_PATH];
1835 char * str = shortname;
1836 char c;
1837 char * path;
1838 const char * save_name = name;
1840 if (strlen (name) >= MAX_PATH)
1842 /* Return a filename which will cause callers to fail. */
1843 strcpy (shortname, "?");
1844 return shortname;
1847 if (is_fat_volume (name, (const char **)&path)) /* truncate to 8.3 */
1849 register int left = 8; /* maximum number of chars in part */
1850 register int extn = 0; /* extension added? */
1851 register int dots = 2; /* maximum number of dots allowed */
1853 while (name < path)
1854 *str++ = *name++; /* skip past UNC header */
1856 while ((c = *name++))
1858 switch ( c )
1860 case '\\':
1861 case '/':
1862 *str++ = '\\';
1863 extn = 0; /* reset extension flags */
1864 dots = 2; /* max 2 dots */
1865 left = 8; /* max length 8 for main part */
1866 break;
1867 case ':':
1868 *str++ = ':';
1869 extn = 0; /* reset extension flags */
1870 dots = 2; /* max 2 dots */
1871 left = 8; /* max length 8 for main part */
1872 break;
1873 case '.':
1874 if ( dots )
1876 /* Convert path components of the form .xxx to _xxx,
1877 but leave . and .. as they are. This allows .emacs
1878 to be read as _emacs, for example. */
1880 if (! *name ||
1881 *name == '.' ||
1882 IS_DIRECTORY_SEP (*name))
1884 *str++ = '.';
1885 dots--;
1887 else
1889 *str++ = '_';
1890 left--;
1891 dots = 0;
1894 else if ( !extn )
1896 *str++ = '.';
1897 extn = 1; /* we've got an extension */
1898 left = 3; /* 3 chars in extension */
1900 else
1902 /* any embedded dots after the first are converted to _ */
1903 *str++ = '_';
1905 break;
1906 case '~':
1907 case '#': /* don't lose these, they're important */
1908 if ( ! left )
1909 str[-1] = c; /* replace last character of part */
1910 /* FALLTHRU */
1911 default:
1912 if ( left )
1914 *str++ = tolower (c); /* map to lower case (looks nicer) */
1915 left--;
1916 dots = 0; /* started a path component */
1918 break;
1921 *str = '\0';
1923 else
1925 strcpy (shortname, name);
1926 unixtodos_filename (shortname);
1929 if (pPath)
1930 *pPath = shortname + (path - save_name);
1932 return shortname;
1935 static int
1936 is_exec (const char * name)
1938 char * p = strrchr (name, '.');
1939 return
1940 (p != NULL
1941 && (xstrcasecmp (p, ".exe") == 0 ||
1942 xstrcasecmp (p, ".com") == 0 ||
1943 xstrcasecmp (p, ".bat") == 0 ||
1944 xstrcasecmp (p, ".cmd") == 0));
1947 /* Emulate the Unix directory procedures opendir, closedir,
1948 and readdir. We can't use the procedures supplied in sysdep.c,
1949 so we provide them here. */
1951 struct direct dir_static; /* simulated directory contents */
1952 static HANDLE dir_find_handle = INVALID_HANDLE_VALUE;
1953 static int dir_is_fat;
1954 static char dir_pathname[MAXPATHLEN+1];
1955 static WIN32_FIND_DATA dir_find_data;
1957 /* Support shares on a network resource as subdirectories of a read-only
1958 root directory. */
1959 static HANDLE wnet_enum_handle = INVALID_HANDLE_VALUE;
1960 HANDLE open_unc_volume (const char *);
1961 char *read_unc_volume (HANDLE, char *, int);
1962 void close_unc_volume (HANDLE);
1964 DIR *
1965 opendir (char *filename)
1967 DIR *dirp;
1969 /* Opening is done by FindFirstFile. However, a read is inherent to
1970 this operation, so we defer the open until read time. */
1972 if (dir_find_handle != INVALID_HANDLE_VALUE)
1973 return NULL;
1974 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
1975 return NULL;
1977 if (is_unc_volume (filename))
1979 wnet_enum_handle = open_unc_volume (filename);
1980 if (wnet_enum_handle == INVALID_HANDLE_VALUE)
1981 return NULL;
1984 if (!(dirp = (DIR *) malloc (sizeof (DIR))))
1985 return NULL;
1987 dirp->dd_fd = 0;
1988 dirp->dd_loc = 0;
1989 dirp->dd_size = 0;
1991 strncpy (dir_pathname, map_w32_filename (filename, NULL), MAXPATHLEN);
1992 dir_pathname[MAXPATHLEN] = '\0';
1993 dir_is_fat = is_fat_volume (filename, NULL);
1995 return dirp;
1998 void
1999 closedir (DIR *dirp)
2001 /* If we have a find-handle open, close it. */
2002 if (dir_find_handle != INVALID_HANDLE_VALUE)
2004 FindClose (dir_find_handle);
2005 dir_find_handle = INVALID_HANDLE_VALUE;
2007 else if (wnet_enum_handle != INVALID_HANDLE_VALUE)
2009 close_unc_volume (wnet_enum_handle);
2010 wnet_enum_handle = INVALID_HANDLE_VALUE;
2012 xfree ((char *) dirp);
2015 struct direct *
2016 readdir (DIR *dirp)
2018 int downcase = !NILP (Vw32_downcase_file_names);
2020 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
2022 if (!read_unc_volume (wnet_enum_handle,
2023 dir_find_data.cFileName,
2024 MAX_PATH))
2025 return NULL;
2027 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
2028 else if (dir_find_handle == INVALID_HANDLE_VALUE)
2030 char filename[MAXNAMLEN + 3];
2031 int ln;
2033 strcpy (filename, dir_pathname);
2034 ln = strlen (filename) - 1;
2035 if (!IS_DIRECTORY_SEP (filename[ln]))
2036 strcat (filename, "\\");
2037 strcat (filename, "*");
2039 dir_find_handle = FindFirstFile (filename, &dir_find_data);
2041 if (dir_find_handle == INVALID_HANDLE_VALUE)
2042 return NULL;
2044 else
2046 if (!FindNextFile (dir_find_handle, &dir_find_data))
2047 return NULL;
2050 /* Emacs never uses this value, so don't bother making it match
2051 value returned by stat(). */
2052 dir_static.d_ino = 1;
2054 strcpy (dir_static.d_name, dir_find_data.cFileName);
2056 /* If the file name in cFileName[] includes `?' characters, it means
2057 the original file name used characters that cannot be represented
2058 by the current ANSI codepage. To avoid total lossage, retrieve
2059 the short 8+3 alias of the long file name. */
2060 if (_mbspbrk (dir_static.d_name, "?"))
2062 strcpy (dir_static.d_name, dir_find_data.cAlternateFileName);
2063 downcase = 1; /* 8+3 aliases are returned in all caps */
2065 dir_static.d_namlen = strlen (dir_static.d_name);
2066 dir_static.d_reclen = sizeof (struct direct) - MAXNAMLEN + 3 +
2067 dir_static.d_namlen - dir_static.d_namlen % 4;
2069 /* If the file name in cFileName[] includes `?' characters, it means
2070 the original file name used characters that cannot be represented
2071 by the current ANSI codepage. To avoid total lossage, retrieve
2072 the short 8+3 alias of the long file name. */
2073 if (_mbspbrk (dir_find_data.cFileName, "?"))
2075 strcpy (dir_static.d_name, dir_find_data.cAlternateFileName);
2076 /* 8+3 aliases are returned in all caps, which could break
2077 various alists that look at filenames' extensions. */
2078 downcase = 1;
2080 else
2081 strcpy (dir_static.d_name, dir_find_data.cFileName);
2082 dir_static.d_namlen = strlen (dir_static.d_name);
2083 if (dir_is_fat)
2084 _strlwr (dir_static.d_name);
2085 else if (downcase)
2087 register char *p;
2088 for (p = dir_static.d_name; *p; p++)
2089 if (*p >= 'a' && *p <= 'z')
2090 break;
2091 if (!*p)
2092 _strlwr (dir_static.d_name);
2095 return &dir_static;
2098 HANDLE
2099 open_unc_volume (const char *path)
2101 NETRESOURCE nr;
2102 HANDLE henum;
2103 int result;
2105 nr.dwScope = RESOURCE_GLOBALNET;
2106 nr.dwType = RESOURCETYPE_DISK;
2107 nr.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
2108 nr.dwUsage = RESOURCEUSAGE_CONTAINER;
2109 nr.lpLocalName = NULL;
2110 nr.lpRemoteName = (LPSTR)map_w32_filename (path, NULL);
2111 nr.lpComment = NULL;
2112 nr.lpProvider = NULL;
2114 result = WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
2115 RESOURCEUSAGE_CONNECTABLE, &nr, &henum);
2117 if (result == NO_ERROR)
2118 return henum;
2119 else
2120 return INVALID_HANDLE_VALUE;
2123 char *
2124 read_unc_volume (HANDLE henum, char *readbuf, int size)
2126 DWORD count;
2127 int result;
2128 DWORD bufsize = 512;
2129 char *buffer;
2130 char *ptr;
2132 count = 1;
2133 buffer = alloca (bufsize);
2134 result = WNetEnumResource (wnet_enum_handle, &count, buffer, &bufsize);
2135 if (result != NO_ERROR)
2136 return NULL;
2138 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
2139 ptr = ((LPNETRESOURCE) buffer)->lpRemoteName;
2140 ptr += 2;
2141 while (*ptr && !IS_DIRECTORY_SEP (*ptr)) ptr++;
2142 ptr++;
2144 strncpy (readbuf, ptr, size);
2145 return readbuf;
2148 void
2149 close_unc_volume (HANDLE henum)
2151 if (henum != INVALID_HANDLE_VALUE)
2152 WNetCloseEnum (henum);
2155 DWORD
2156 unc_volume_file_attributes (const char *path)
2158 HANDLE henum;
2159 DWORD attrs;
2161 henum = open_unc_volume (path);
2162 if (henum == INVALID_HANDLE_VALUE)
2163 return -1;
2165 attrs = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY;
2167 close_unc_volume (henum);
2169 return attrs;
2172 /* Ensure a network connection is authenticated. */
2173 static void
2174 logon_network_drive (const char *path)
2176 NETRESOURCE resource;
2177 char share[MAX_PATH];
2178 int i, n_slashes;
2179 char drive[4];
2181 sprintf (drive, "%c:\\", path[0]);
2183 /* Only logon to networked drives. */
2184 if ((!IS_DIRECTORY_SEP (path[0]) || !IS_DIRECTORY_SEP (path[1]))
2185 && GetDriveType (drive) != DRIVE_REMOTE)
2186 return;
2188 n_slashes = 2;
2189 strncpy (share, path, MAX_PATH);
2190 /* Truncate to just server and share name. */
2191 for (i = 2; i < MAX_PATH; i++)
2193 if (IS_DIRECTORY_SEP (share[i]) && ++n_slashes > 3)
2195 share[i] = '\0';
2196 break;
2200 resource.dwType = RESOURCETYPE_DISK;
2201 resource.lpLocalName = NULL;
2202 resource.lpRemoteName = share;
2203 resource.lpProvider = NULL;
2205 WNetAddConnection2 (&resource, NULL, NULL, CONNECT_INTERACTIVE);
2208 /* Shadow some MSVC runtime functions to map requests for long filenames
2209 to reasonable short names if necessary. This was originally added to
2210 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
2211 long file names. */
2214 sys_access (const char * path, int mode)
2216 DWORD attributes;
2218 /* MSVC implementation doesn't recognize D_OK. */
2219 path = map_w32_filename (path, NULL);
2220 if (is_unc_volume (path))
2222 attributes = unc_volume_file_attributes (path);
2223 if (attributes == -1) {
2224 errno = EACCES;
2225 return -1;
2228 else if ((attributes = GetFileAttributes (path)) == -1)
2230 /* Should try mapping GetLastError to errno; for now just indicate
2231 that path doesn't exist. */
2232 errno = EACCES;
2233 return -1;
2235 if ((mode & X_OK) != 0 && !is_exec (path))
2237 errno = EACCES;
2238 return -1;
2240 if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0)
2242 errno = EACCES;
2243 return -1;
2245 if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
2247 errno = EACCES;
2248 return -1;
2250 return 0;
2254 sys_chdir (const char * path)
2256 return _chdir (map_w32_filename (path, NULL));
2260 sys_chmod (const char * path, int mode)
2262 return _chmod (map_w32_filename (path, NULL), mode);
2266 sys_chown (const char *path, uid_t owner, gid_t group)
2268 if (sys_chmod (path, S_IREAD) == -1) /* check if file exists */
2269 return -1;
2270 return 0;
2274 sys_creat (const char * path, int mode)
2276 return _creat (map_w32_filename (path, NULL), mode);
2279 FILE *
2280 sys_fopen(const char * path, const char * mode)
2282 int fd;
2283 int oflag;
2284 const char * mode_save = mode;
2286 /* Force all file handles to be non-inheritable. This is necessary to
2287 ensure child processes don't unwittingly inherit handles that might
2288 prevent future file access. */
2290 if (mode[0] == 'r')
2291 oflag = O_RDONLY;
2292 else if (mode[0] == 'w' || mode[0] == 'a')
2293 oflag = O_WRONLY | O_CREAT | O_TRUNC;
2294 else
2295 return NULL;
2297 /* Only do simplistic option parsing. */
2298 while (*++mode)
2299 if (mode[0] == '+')
2301 oflag &= ~(O_RDONLY | O_WRONLY);
2302 oflag |= O_RDWR;
2304 else if (mode[0] == 'b')
2306 oflag &= ~O_TEXT;
2307 oflag |= O_BINARY;
2309 else if (mode[0] == 't')
2311 oflag &= ~O_BINARY;
2312 oflag |= O_TEXT;
2314 else break;
2316 fd = _open (map_w32_filename (path, NULL), oflag | _O_NOINHERIT, 0644);
2317 if (fd < 0)
2318 return NULL;
2320 return _fdopen (fd, mode_save);
2323 /* This only works on NTFS volumes, but is useful to have. */
2325 sys_link (const char * old, const char * new)
2327 HANDLE fileh;
2328 int result = -1;
2329 char oldname[MAX_PATH], newname[MAX_PATH];
2331 if (old == NULL || new == NULL)
2333 errno = ENOENT;
2334 return -1;
2337 strcpy (oldname, map_w32_filename (old, NULL));
2338 strcpy (newname, map_w32_filename (new, NULL));
2340 fileh = CreateFile (oldname, 0, 0, NULL, OPEN_EXISTING,
2341 FILE_FLAG_BACKUP_SEMANTICS, NULL);
2342 if (fileh != INVALID_HANDLE_VALUE)
2344 int wlen;
2346 /* Confusingly, the "alternate" stream name field does not apply
2347 when restoring a hard link, and instead contains the actual
2348 stream data for the link (ie. the name of the link to create).
2349 The WIN32_STREAM_ID structure before the cStreamName field is
2350 the stream header, which is then immediately followed by the
2351 stream data. */
2353 struct {
2354 WIN32_STREAM_ID wid;
2355 WCHAR wbuffer[MAX_PATH]; /* extra space for link name */
2356 } data;
2358 wlen = MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, newname, -1,
2359 data.wid.cStreamName, MAX_PATH);
2360 if (wlen > 0)
2362 LPVOID context = NULL;
2363 DWORD wbytes = 0;
2365 data.wid.dwStreamId = BACKUP_LINK;
2366 data.wid.dwStreamAttributes = 0;
2367 data.wid.Size.LowPart = wlen * sizeof(WCHAR);
2368 data.wid.Size.HighPart = 0;
2369 data.wid.dwStreamNameSize = 0;
2371 if (BackupWrite (fileh, (LPBYTE)&data,
2372 offsetof (WIN32_STREAM_ID, cStreamName)
2373 + data.wid.Size.LowPart,
2374 &wbytes, FALSE, FALSE, &context)
2375 && BackupWrite (fileh, NULL, 0, &wbytes, TRUE, FALSE, &context))
2377 /* succeeded */
2378 result = 0;
2380 else
2382 /* Should try mapping GetLastError to errno; for now just
2383 indicate a general error (eg. links not supported). */
2384 errno = EINVAL; // perhaps EMLINK?
2388 CloseHandle (fileh);
2390 else
2391 errno = ENOENT;
2393 return result;
2397 sys_mkdir (const char * path)
2399 return _mkdir (map_w32_filename (path, NULL));
2402 /* Because of long name mapping issues, we need to implement this
2403 ourselves. Also, MSVC's _mktemp returns NULL when it can't generate
2404 a unique name, instead of setting the input template to an empty
2405 string.
2407 Standard algorithm seems to be use pid or tid with a letter on the
2408 front (in place of the 6 X's) and cycle through the letters to find a
2409 unique name. We extend that to allow any reasonable character as the
2410 first of the 6 X's. */
2411 char *
2412 sys_mktemp (char * template)
2414 char * p;
2415 int i;
2416 unsigned uid = GetCurrentThreadId ();
2417 static char first_char[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
2419 if (template == NULL)
2420 return NULL;
2421 p = template + strlen (template);
2422 i = 5;
2423 /* replace up to the last 5 X's with uid in decimal */
2424 while (--p >= template && p[0] == 'X' && --i >= 0)
2426 p[0] = '0' + uid % 10;
2427 uid /= 10;
2430 if (i < 0 && p[0] == 'X')
2432 i = 0;
2435 int save_errno = errno;
2436 p[0] = first_char[i];
2437 if (sys_access (template, 0) < 0)
2439 errno = save_errno;
2440 return template;
2443 while (++i < sizeof (first_char));
2446 /* Template is badly formed or else we can't generate a unique name,
2447 so return empty string */
2448 template[0] = 0;
2449 return template;
2453 sys_open (const char * path, int oflag, int mode)
2455 const char* mpath = map_w32_filename (path, NULL);
2456 /* Try to open file without _O_CREAT, to be able to write to hidden
2457 and system files. Force all file handles to be
2458 non-inheritable. */
2459 int res = _open (mpath, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
2460 if (res >= 0)
2461 return res;
2462 return _open (mpath, oflag | _O_NOINHERIT, mode);
2466 sys_rename (const char * oldname, const char * newname)
2468 BOOL result;
2469 char temp[MAX_PATH];
2471 /* MoveFile on Windows 95 doesn't correctly change the short file name
2472 alias in a number of circumstances (it is not easy to predict when
2473 just by looking at oldname and newname, unfortunately). In these
2474 cases, renaming through a temporary name avoids the problem.
2476 A second problem on Windows 95 is that renaming through a temp name when
2477 newname is uppercase fails (the final long name ends up in
2478 lowercase, although the short alias might be uppercase) UNLESS the
2479 long temp name is not 8.3.
2481 So, on Windows 95 we always rename through a temp name, and we make sure
2482 the temp name has a long extension to ensure correct renaming. */
2484 strcpy (temp, map_w32_filename (oldname, NULL));
2486 if (os_subtype == OS_WIN95)
2488 char * o;
2489 char * p;
2490 int i = 0;
2492 oldname = map_w32_filename (oldname, NULL);
2493 if (o = strrchr (oldname, '\\'))
2494 o++;
2495 else
2496 o = (char *) oldname;
2498 if (p = strrchr (temp, '\\'))
2499 p++;
2500 else
2501 p = temp;
2505 /* Force temp name to require a manufactured 8.3 alias - this
2506 seems to make the second rename work properly. */
2507 sprintf (p, "_.%s.%u", o, i);
2508 i++;
2509 result = rename (oldname, temp);
2511 /* This loop must surely terminate! */
2512 while (result < 0 && errno == EEXIST);
2513 if (result < 0)
2514 return -1;
2517 /* Emulate Unix behavior - newname is deleted if it already exists
2518 (at least if it is a file; don't do this for directories).
2520 Since we mustn't do this if we are just changing the case of the
2521 file name (we would end up deleting the file we are trying to
2522 rename!), we let rename detect if the destination file already
2523 exists - that way we avoid the possible pitfalls of trying to
2524 determine ourselves whether two names really refer to the same
2525 file, which is not always possible in the general case. (Consider
2526 all the permutations of shared or subst'd drives, etc.) */
2528 newname = map_w32_filename (newname, NULL);
2529 result = rename (temp, newname);
2531 if (result < 0
2532 && errno == EEXIST
2533 && _chmod (newname, 0666) == 0
2534 && _unlink (newname) == 0)
2535 result = rename (temp, newname);
2537 return result;
2541 sys_rmdir (const char * path)
2543 return _rmdir (map_w32_filename (path, NULL));
2547 sys_unlink (const char * path)
2549 path = map_w32_filename (path, NULL);
2551 /* On Unix, unlink works without write permission. */
2552 _chmod (path, 0666);
2553 return _unlink (path);
2556 static FILETIME utc_base_ft;
2557 static long double utc_base;
2558 static int init = 0;
2560 static time_t
2561 convert_time (FILETIME ft)
2563 long double ret;
2565 if (!init)
2567 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
2568 SYSTEMTIME st;
2570 st.wYear = 1970;
2571 st.wMonth = 1;
2572 st.wDay = 1;
2573 st.wHour = 0;
2574 st.wMinute = 0;
2575 st.wSecond = 0;
2576 st.wMilliseconds = 0;
2578 SystemTimeToFileTime (&st, &utc_base_ft);
2579 utc_base = (long double) utc_base_ft.dwHighDateTime
2580 * 4096.0L * 1024.0L * 1024.0L + utc_base_ft.dwLowDateTime;
2581 init = 1;
2584 if (CompareFileTime (&ft, &utc_base_ft) < 0)
2585 return 0;
2587 ret = (long double) ft.dwHighDateTime
2588 * 4096.0L * 1024.0L * 1024.0L + ft.dwLowDateTime;
2589 ret -= utc_base;
2590 return (time_t) (ret * 1e-7L);
2593 void
2594 convert_from_time_t (time_t time, FILETIME * pft)
2596 long double tmp;
2598 if (!init)
2600 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
2601 SYSTEMTIME st;
2603 st.wYear = 1970;
2604 st.wMonth = 1;
2605 st.wDay = 1;
2606 st.wHour = 0;
2607 st.wMinute = 0;
2608 st.wSecond = 0;
2609 st.wMilliseconds = 0;
2611 SystemTimeToFileTime (&st, &utc_base_ft);
2612 utc_base = (long double) utc_base_ft.dwHighDateTime
2613 * 4096 * 1024 * 1024 + utc_base_ft.dwLowDateTime;
2614 init = 1;
2617 /* time in 100ns units since 1-Jan-1601 */
2618 tmp = (long double) time * 1e7 + utc_base;
2619 pft->dwHighDateTime = (DWORD) (tmp / (4096.0 * 1024 * 1024));
2620 pft->dwLowDateTime = (DWORD) (tmp - (4096.0 * 1024 * 1024) * pft->dwHighDateTime);
2623 #if 0
2624 /* No reason to keep this; faking inode values either by hashing or even
2625 using the file index from GetInformationByHandle, is not perfect and
2626 so by default Emacs doesn't use the inode values on Windows.
2627 Instead, we now determine file-truename correctly (except for
2628 possible drive aliasing etc). */
2630 /* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
2631 static unsigned
2632 hashval (const unsigned char * str)
2634 unsigned h = 0;
2635 while (*str)
2637 h = (h << 4) + *str++;
2638 h ^= (h >> 28);
2640 return h;
2643 /* Return the hash value of the canonical pathname, excluding the
2644 drive/UNC header, to get a hopefully unique inode number. */
2645 static DWORD
2646 generate_inode_val (const char * name)
2648 char fullname[ MAX_PATH ];
2649 char * p;
2650 unsigned hash;
2652 /* Get the truly canonical filename, if it exists. (Note: this
2653 doesn't resolve aliasing due to subst commands, or recognise hard
2654 links. */
2655 if (!w32_get_long_filename ((char *)name, fullname, MAX_PATH))
2656 abort ();
2658 parse_root (fullname, &p);
2659 /* Normal W32 filesystems are still case insensitive. */
2660 _strlwr (p);
2661 return hashval (p);
2664 #endif
2666 static PSECURITY_DESCRIPTOR
2667 get_file_security_desc (const char *fname)
2669 PSECURITY_DESCRIPTOR psd = NULL;
2670 DWORD sd_len, err;
2671 SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION
2672 | GROUP_SECURITY_INFORMATION /* | DACL_SECURITY_INFORMATION */ ;
2674 if (!get_file_security (fname, si, psd, 0, &sd_len))
2676 err = GetLastError ();
2677 if (err != ERROR_INSUFFICIENT_BUFFER)
2678 return NULL;
2681 psd = xmalloc (sd_len);
2682 if (!get_file_security (fname, si, psd, sd_len, &sd_len))
2684 xfree (psd);
2685 return NULL;
2688 return psd;
2691 static DWORD
2692 get_rid (PSID sid)
2694 unsigned n_subauthorities;
2696 /* Use the last sub-authority value of the RID, the relative
2697 portion of the SID, as user/group ID. */
2698 n_subauthorities = *get_sid_sub_authority_count (sid);
2699 if (n_subauthorities < 1)
2700 return 0; /* the "World" RID */
2701 return *get_sid_sub_authority (sid, n_subauthorities - 1);
2704 #define UID 1
2705 #define GID 2
2707 static int
2708 get_name_and_id (PSECURITY_DESCRIPTOR psd, const char *fname,
2709 int *id, char *nm, int what)
2711 PSID sid = NULL;
2712 char machine[MAX_COMPUTERNAME_LENGTH+1];
2713 BOOL dflt;
2714 SID_NAME_USE ignore;
2715 char name[UNLEN+1];
2716 DWORD name_len = sizeof (name);
2717 char domain[1024];
2718 DWORD domain_len = sizeof(domain);
2719 char *mp = NULL;
2720 int use_dflt = 0;
2721 int result;
2723 if (what == UID)
2724 result = get_security_descriptor_owner (psd, &sid, &dflt);
2725 else if (what == GID)
2726 result = get_security_descriptor_group (psd, &sid, &dflt);
2727 else
2728 result = 0;
2730 if (!result || !is_valid_sid (sid))
2731 use_dflt = 1;
2732 else
2734 /* If FNAME is a UNC, we need to lookup account on the
2735 specified machine. */
2736 if (IS_DIRECTORY_SEP (fname[0]) && IS_DIRECTORY_SEP (fname[1])
2737 && fname[2] != '\0')
2739 const char *s;
2740 char *p;
2742 for (s = fname + 2, p = machine;
2743 *s && !IS_DIRECTORY_SEP (*s); s++, p++)
2744 *p = *s;
2745 *p = '\0';
2746 mp = machine;
2749 if (!lookup_account_sid (mp, sid, name, &name_len,
2750 domain, &domain_len, &ignore)
2751 || name_len > UNLEN+1)
2752 use_dflt = 1;
2753 else
2755 *id = get_rid (sid);
2756 strcpy (nm, name);
2759 return use_dflt;
2762 static void
2763 get_file_owner_and_group (
2764 PSECURITY_DESCRIPTOR psd,
2765 const char *fname,
2766 struct stat *st)
2768 int dflt_usr = 0, dflt_grp = 0;
2770 if (!psd)
2772 dflt_usr = 1;
2773 dflt_grp = 1;
2775 else
2777 if (get_name_and_id (psd, fname, &st->st_uid, st->st_uname, UID))
2778 dflt_usr = 1;
2779 if (get_name_and_id (psd, fname, &st->st_gid, st->st_gname, GID))
2780 dflt_grp = 1;
2782 /* Consider files to belong to current user/group, if we cannot get
2783 more accurate information. */
2784 if (dflt_usr)
2786 st->st_uid = dflt_passwd.pw_uid;
2787 strcpy (st->st_uname, dflt_passwd.pw_name);
2789 if (dflt_grp)
2791 st->st_gid = dflt_passwd.pw_gid;
2792 strcpy (st->st_gname, dflt_group.gr_name);
2796 /* MSVC stat function can't cope with UNC names and has other bugs, so
2797 replace it with our own. This also allows us to calculate consistent
2798 inode values without hacks in the main Emacs code. */
2800 stat (const char * path, struct stat * buf)
2802 char *name, *r;
2803 WIN32_FIND_DATA wfd;
2804 HANDLE fh;
2805 unsigned __int64 fake_inode;
2806 int permission;
2807 int len;
2808 int rootdir = FALSE;
2809 PSECURITY_DESCRIPTOR psd = NULL;
2811 if (path == NULL || buf == NULL)
2813 errno = EFAULT;
2814 return -1;
2817 name = (char *) map_w32_filename (path, &path);
2818 /* Must be valid filename, no wild cards or other invalid
2819 characters. We use _mbspbrk to support multibyte strings that
2820 might look to strpbrk as if they included literal *, ?, and other
2821 characters mentioned below that are disallowed by Windows
2822 filesystems. */
2823 if (_mbspbrk (name, "*?|<>\""))
2825 errno = ENOENT;
2826 return -1;
2829 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
2830 r = IS_DEVICE_SEP (name[1]) ? &name[2] : name;
2831 if (IS_DIRECTORY_SEP (r[0]) && r[1] == '.' && r[2] == '.' && r[3] == '\0')
2833 r[1] = r[2] = '\0';
2836 /* Remove trailing directory separator, unless name is the root
2837 directory of a drive or UNC volume in which case ensure there
2838 is a trailing separator. */
2839 len = strlen (name);
2840 rootdir = (path >= name + len - 1
2841 && (IS_DIRECTORY_SEP (*path) || *path == 0));
2842 name = strcpy (alloca (len + 2), name);
2844 if (is_unc_volume (name))
2846 DWORD attrs = unc_volume_file_attributes (name);
2848 if (attrs == -1)
2849 return -1;
2851 memset (&wfd, 0, sizeof (wfd));
2852 wfd.dwFileAttributes = attrs;
2853 wfd.ftCreationTime = utc_base_ft;
2854 wfd.ftLastAccessTime = utc_base_ft;
2855 wfd.ftLastWriteTime = utc_base_ft;
2856 strcpy (wfd.cFileName, name);
2858 else if (rootdir)
2860 if (!IS_DIRECTORY_SEP (name[len-1]))
2861 strcat (name, "\\");
2862 if (GetDriveType (name) < 2)
2864 errno = ENOENT;
2865 return -1;
2867 memset (&wfd, 0, sizeof (wfd));
2868 wfd.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
2869 wfd.ftCreationTime = utc_base_ft;
2870 wfd.ftLastAccessTime = utc_base_ft;
2871 wfd.ftLastWriteTime = utc_base_ft;
2872 strcpy (wfd.cFileName, name);
2874 else
2876 if (IS_DIRECTORY_SEP (name[len-1]))
2877 name[len - 1] = 0;
2879 /* (This is hacky, but helps when doing file completions on
2880 network drives.) Optimize by using information available from
2881 active readdir if possible. */
2882 len = strlen (dir_pathname);
2883 if (IS_DIRECTORY_SEP (dir_pathname[len-1]))
2884 len--;
2885 if (dir_find_handle != INVALID_HANDLE_VALUE
2886 && strnicmp (name, dir_pathname, len) == 0
2887 && IS_DIRECTORY_SEP (name[len])
2888 && xstrcasecmp (name + len + 1, dir_static.d_name) == 0)
2890 /* This was the last entry returned by readdir. */
2891 wfd = dir_find_data;
2893 else
2895 logon_network_drive (name);
2897 fh = FindFirstFile (name, &wfd);
2898 if (fh == INVALID_HANDLE_VALUE)
2900 errno = ENOENT;
2901 return -1;
2903 FindClose (fh);
2907 if (!(NILP (Vw32_get_true_file_attributes)
2908 || (EQ (Vw32_get_true_file_attributes, Qlocal) &&
2909 GetDriveType (name) != DRIVE_FIXED))
2910 /* No access rights required to get info. */
2911 && (fh = CreateFile (name, 0, 0, NULL, OPEN_EXISTING,
2912 FILE_FLAG_BACKUP_SEMANTICS, NULL))
2913 != INVALID_HANDLE_VALUE)
2915 /* This is more accurate in terms of gettting the correct number
2916 of links, but is quite slow (it is noticeable when Emacs is
2917 making a list of file name completions). */
2918 BY_HANDLE_FILE_INFORMATION info;
2920 if (GetFileInformationByHandle (fh, &info))
2922 buf->st_nlink = info.nNumberOfLinks;
2923 /* Might as well use file index to fake inode values, but this
2924 is not guaranteed to be unique unless we keep a handle open
2925 all the time (even then there are situations where it is
2926 not unique). Reputedly, there are at most 48 bits of info
2927 (on NTFS, presumably less on FAT). */
2928 fake_inode = info.nFileIndexHigh;
2929 fake_inode <<= 32;
2930 fake_inode += info.nFileIndexLow;
2932 else
2934 buf->st_nlink = 1;
2935 fake_inode = 0;
2938 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
2940 buf->st_mode = S_IFDIR;
2942 else
2944 switch (GetFileType (fh))
2946 case FILE_TYPE_DISK:
2947 buf->st_mode = S_IFREG;
2948 break;
2949 case FILE_TYPE_PIPE:
2950 buf->st_mode = S_IFIFO;
2951 break;
2952 case FILE_TYPE_CHAR:
2953 case FILE_TYPE_UNKNOWN:
2954 default:
2955 buf->st_mode = S_IFCHR;
2958 CloseHandle (fh);
2959 psd = get_file_security_desc (name);
2960 get_file_owner_and_group (psd, name, buf);
2962 else
2964 /* Don't bother to make this information more accurate. */
2965 buf->st_mode = (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ?
2966 S_IFDIR : S_IFREG;
2967 buf->st_nlink = 1;
2968 fake_inode = 0;
2970 get_file_owner_and_group (NULL, name, buf);
2972 xfree (psd);
2974 #if 0
2975 /* Not sure if there is any point in this. */
2976 if (!NILP (Vw32_generate_fake_inodes))
2977 fake_inode = generate_inode_val (name);
2978 else if (fake_inode == 0)
2980 /* For want of something better, try to make everything unique. */
2981 static DWORD gen_num = 0;
2982 fake_inode = ++gen_num;
2984 #endif
2986 /* MSVC defines _ino_t to be short; other libc's might not. */
2987 if (sizeof (buf->st_ino) == 2)
2988 buf->st_ino = fake_inode ^ (fake_inode >> 16);
2989 else
2990 buf->st_ino = fake_inode;
2992 /* volume_info is set indirectly by map_w32_filename */
2993 buf->st_dev = volume_info.serialnum;
2994 buf->st_rdev = volume_info.serialnum;
2997 buf->st_size = wfd.nFileSizeHigh;
2998 buf->st_size <<= 32;
2999 buf->st_size += wfd.nFileSizeLow;
3001 /* Convert timestamps to Unix format. */
3002 buf->st_mtime = convert_time (wfd.ftLastWriteTime);
3003 buf->st_atime = convert_time (wfd.ftLastAccessTime);
3004 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
3005 buf->st_ctime = convert_time (wfd.ftCreationTime);
3006 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
3008 /* determine rwx permissions */
3009 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
3010 permission = S_IREAD;
3011 else
3012 permission = S_IREAD | S_IWRITE;
3014 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
3015 permission |= S_IEXEC;
3016 else if (is_exec (name))
3017 permission |= S_IEXEC;
3019 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
3021 return 0;
3024 /* Provide fstat and utime as well as stat for consistent handling of
3025 file timestamps. */
3027 fstat (int desc, struct stat * buf)
3029 HANDLE fh = (HANDLE) _get_osfhandle (desc);
3030 BY_HANDLE_FILE_INFORMATION info;
3031 unsigned __int64 fake_inode;
3032 int permission;
3034 switch (GetFileType (fh) & ~FILE_TYPE_REMOTE)
3036 case FILE_TYPE_DISK:
3037 buf->st_mode = S_IFREG;
3038 if (!GetFileInformationByHandle (fh, &info))
3040 errno = EACCES;
3041 return -1;
3043 break;
3044 case FILE_TYPE_PIPE:
3045 buf->st_mode = S_IFIFO;
3046 goto non_disk;
3047 case FILE_TYPE_CHAR:
3048 case FILE_TYPE_UNKNOWN:
3049 default:
3050 buf->st_mode = S_IFCHR;
3051 non_disk:
3052 memset (&info, 0, sizeof (info));
3053 info.dwFileAttributes = 0;
3054 info.ftCreationTime = utc_base_ft;
3055 info.ftLastAccessTime = utc_base_ft;
3056 info.ftLastWriteTime = utc_base_ft;
3059 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
3060 buf->st_mode = S_IFDIR;
3062 buf->st_nlink = info.nNumberOfLinks;
3063 /* Might as well use file index to fake inode values, but this
3064 is not guaranteed to be unique unless we keep a handle open
3065 all the time (even then there are situations where it is
3066 not unique). Reputedly, there are at most 48 bits of info
3067 (on NTFS, presumably less on FAT). */
3068 fake_inode = info.nFileIndexHigh;
3069 fake_inode <<= 32;
3070 fake_inode += info.nFileIndexLow;
3072 /* MSVC defines _ino_t to be short; other libc's might not. */
3073 if (sizeof (buf->st_ino) == 2)
3074 buf->st_ino = fake_inode ^ (fake_inode >> 16);
3075 else
3076 buf->st_ino = fake_inode;
3078 /* Consider files to belong to current user.
3079 FIXME: this should use GetSecurityInfo API, but it is only
3080 available for _WIN32_WINNT >= 0x501. */
3081 buf->st_uid = dflt_passwd.pw_uid;
3082 buf->st_gid = dflt_passwd.pw_gid;
3083 strcpy (buf->st_uname, dflt_passwd.pw_name);
3084 strcpy (buf->st_gname, dflt_group.gr_name);
3086 buf->st_dev = info.dwVolumeSerialNumber;
3087 buf->st_rdev = info.dwVolumeSerialNumber;
3089 buf->st_size = info.nFileSizeHigh;
3090 buf->st_size <<= 32;
3091 buf->st_size += info.nFileSizeLow;
3093 /* Convert timestamps to Unix format. */
3094 buf->st_mtime = convert_time (info.ftLastWriteTime);
3095 buf->st_atime = convert_time (info.ftLastAccessTime);
3096 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
3097 buf->st_ctime = convert_time (info.ftCreationTime);
3098 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
3100 /* determine rwx permissions */
3101 if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
3102 permission = S_IREAD;
3103 else
3104 permission = S_IREAD | S_IWRITE;
3106 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
3107 permission |= S_IEXEC;
3108 else
3110 #if 0 /* no way of knowing the filename */
3111 char * p = strrchr (name, '.');
3112 if (p != NULL &&
3113 (xstrcasecmp (p, ".exe") == 0 ||
3114 xstrcasecmp (p, ".com") == 0 ||
3115 xstrcasecmp (p, ".bat") == 0 ||
3116 xstrcasecmp (p, ".cmd") == 0))
3117 permission |= S_IEXEC;
3118 #endif
3121 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
3123 return 0;
3127 utime (const char *name, struct utimbuf *times)
3129 struct utimbuf deftime;
3130 HANDLE fh;
3131 FILETIME mtime;
3132 FILETIME atime;
3134 if (times == NULL)
3136 deftime.modtime = deftime.actime = time (NULL);
3137 times = &deftime;
3140 /* Need write access to set times. */
3141 fh = CreateFile (name, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
3142 0, OPEN_EXISTING, 0, NULL);
3143 if (fh)
3145 convert_from_time_t (times->actime, &atime);
3146 convert_from_time_t (times->modtime, &mtime);
3147 if (!SetFileTime (fh, NULL, &atime, &mtime))
3149 CloseHandle (fh);
3150 errno = EACCES;
3151 return -1;
3153 CloseHandle (fh);
3155 else
3157 errno = EINVAL;
3158 return -1;
3160 return 0;
3163 #ifdef HAVE_SOCKETS
3165 /* Wrappers for winsock functions to map between our file descriptors
3166 and winsock's handles; also set h_errno for convenience.
3168 To allow Emacs to run on systems which don't have winsock support
3169 installed, we dynamically link to winsock on startup if present, and
3170 otherwise provide the minimum necessary functionality
3171 (eg. gethostname). */
3173 /* function pointers for relevant socket functions */
3174 int (PASCAL *pfn_WSAStartup) (WORD wVersionRequired, LPWSADATA lpWSAData);
3175 void (PASCAL *pfn_WSASetLastError) (int iError);
3176 int (PASCAL *pfn_WSAGetLastError) (void);
3177 int (PASCAL *pfn_WSAEventSelect) (SOCKET s, HANDLE hEventObject, long lNetworkEvents);
3178 HANDLE (PASCAL *pfn_WSACreateEvent) (void);
3179 int (PASCAL *pfn_WSACloseEvent) (HANDLE hEvent);
3180 int (PASCAL *pfn_socket) (int af, int type, int protocol);
3181 int (PASCAL *pfn_bind) (SOCKET s, const struct sockaddr *addr, int namelen);
3182 int (PASCAL *pfn_connect) (SOCKET s, const struct sockaddr *addr, int namelen);
3183 int (PASCAL *pfn_ioctlsocket) (SOCKET s, long cmd, u_long *argp);
3184 int (PASCAL *pfn_recv) (SOCKET s, char * buf, int len, int flags);
3185 int (PASCAL *pfn_send) (SOCKET s, const char * buf, int len, int flags);
3186 int (PASCAL *pfn_closesocket) (SOCKET s);
3187 int (PASCAL *pfn_shutdown) (SOCKET s, int how);
3188 int (PASCAL *pfn_WSACleanup) (void);
3190 u_short (PASCAL *pfn_htons) (u_short hostshort);
3191 u_short (PASCAL *pfn_ntohs) (u_short netshort);
3192 unsigned long (PASCAL *pfn_inet_addr) (const char * cp);
3193 int (PASCAL *pfn_gethostname) (char * name, int namelen);
3194 struct hostent * (PASCAL *pfn_gethostbyname) (const char * name);
3195 struct servent * (PASCAL *pfn_getservbyname) (const char * name, const char * proto);
3196 int (PASCAL *pfn_getpeername) (SOCKET s, struct sockaddr *addr, int * namelen);
3197 int (PASCAL *pfn_setsockopt) (SOCKET s, int level, int optname,
3198 const char * optval, int optlen);
3199 int (PASCAL *pfn_listen) (SOCKET s, int backlog);
3200 int (PASCAL *pfn_getsockname) (SOCKET s, struct sockaddr * name,
3201 int * namelen);
3202 SOCKET (PASCAL *pfn_accept) (SOCKET s, struct sockaddr * addr, int * addrlen);
3203 int (PASCAL *pfn_recvfrom) (SOCKET s, char * buf, int len, int flags,
3204 struct sockaddr * from, int * fromlen);
3205 int (PASCAL *pfn_sendto) (SOCKET s, const char * buf, int len, int flags,
3206 const struct sockaddr * to, int tolen);
3208 /* SetHandleInformation is only needed to make sockets non-inheritable. */
3209 BOOL (WINAPI *pfn_SetHandleInformation) (HANDLE object, DWORD mask, DWORD flags);
3210 #ifndef HANDLE_FLAG_INHERIT
3211 #define HANDLE_FLAG_INHERIT 1
3212 #endif
3214 HANDLE winsock_lib;
3215 static int winsock_inuse;
3217 BOOL
3218 term_winsock (void)
3220 if (winsock_lib != NULL && winsock_inuse == 0)
3222 /* Not sure what would cause WSAENETDOWN, or even if it can happen
3223 after WSAStartup returns successfully, but it seems reasonable
3224 to allow unloading winsock anyway in that case. */
3225 if (pfn_WSACleanup () == 0 ||
3226 pfn_WSAGetLastError () == WSAENETDOWN)
3228 if (FreeLibrary (winsock_lib))
3229 winsock_lib = NULL;
3230 return TRUE;
3233 return FALSE;
3236 BOOL
3237 init_winsock (int load_now)
3239 WSADATA winsockData;
3241 if (winsock_lib != NULL)
3242 return TRUE;
3244 pfn_SetHandleInformation = NULL;
3245 pfn_SetHandleInformation
3246 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
3247 "SetHandleInformation");
3249 winsock_lib = LoadLibrary ("Ws2_32.dll");
3251 if (winsock_lib != NULL)
3253 /* dynamically link to socket functions */
3255 #define LOAD_PROC(fn) \
3256 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
3257 goto fail;
3259 LOAD_PROC( WSAStartup );
3260 LOAD_PROC( WSASetLastError );
3261 LOAD_PROC( WSAGetLastError );
3262 LOAD_PROC( WSAEventSelect );
3263 LOAD_PROC( WSACreateEvent );
3264 LOAD_PROC( WSACloseEvent );
3265 LOAD_PROC( socket );
3266 LOAD_PROC( bind );
3267 LOAD_PROC( connect );
3268 LOAD_PROC( ioctlsocket );
3269 LOAD_PROC( recv );
3270 LOAD_PROC( send );
3271 LOAD_PROC( closesocket );
3272 LOAD_PROC( shutdown );
3273 LOAD_PROC( htons );
3274 LOAD_PROC( ntohs );
3275 LOAD_PROC( inet_addr );
3276 LOAD_PROC( gethostname );
3277 LOAD_PROC( gethostbyname );
3278 LOAD_PROC( getservbyname );
3279 LOAD_PROC( getpeername );
3280 LOAD_PROC( WSACleanup );
3281 LOAD_PROC( setsockopt );
3282 LOAD_PROC( listen );
3283 LOAD_PROC( getsockname );
3284 LOAD_PROC( accept );
3285 LOAD_PROC( recvfrom );
3286 LOAD_PROC( sendto );
3287 #undef LOAD_PROC
3289 /* specify version 1.1 of winsock */
3290 if (pfn_WSAStartup (0x101, &winsockData) == 0)
3292 if (winsockData.wVersion != 0x101)
3293 goto fail;
3295 if (!load_now)
3297 /* Report that winsock exists and is usable, but leave
3298 socket functions disabled. I am assuming that calling
3299 WSAStartup does not require any network interaction,
3300 and in particular does not cause or require a dial-up
3301 connection to be established. */
3303 pfn_WSACleanup ();
3304 FreeLibrary (winsock_lib);
3305 winsock_lib = NULL;
3307 winsock_inuse = 0;
3308 return TRUE;
3311 fail:
3312 FreeLibrary (winsock_lib);
3313 winsock_lib = NULL;
3316 return FALSE;
3320 int h_errno = 0;
3322 /* function to set h_errno for compatibility; map winsock error codes to
3323 normal system codes where they overlap (non-overlapping definitions
3324 are already in <sys/socket.h> */
3325 static void
3326 set_errno ()
3328 if (winsock_lib == NULL)
3329 h_errno = EINVAL;
3330 else
3331 h_errno = pfn_WSAGetLastError ();
3333 switch (h_errno)
3335 case WSAEACCES: h_errno = EACCES; break;
3336 case WSAEBADF: h_errno = EBADF; break;
3337 case WSAEFAULT: h_errno = EFAULT; break;
3338 case WSAEINTR: h_errno = EINTR; break;
3339 case WSAEINVAL: h_errno = EINVAL; break;
3340 case WSAEMFILE: h_errno = EMFILE; break;
3341 case WSAENAMETOOLONG: h_errno = ENAMETOOLONG; break;
3342 case WSAENOTEMPTY: h_errno = ENOTEMPTY; break;
3344 errno = h_errno;
3347 static void
3348 check_errno ()
3350 if (h_errno == 0 && winsock_lib != NULL)
3351 pfn_WSASetLastError (0);
3354 /* Extend strerror to handle the winsock-specific error codes. */
3355 struct {
3356 int errnum;
3357 char * msg;
3358 } _wsa_errlist[] = {
3359 WSAEINTR , "Interrupted function call",
3360 WSAEBADF , "Bad file descriptor",
3361 WSAEACCES , "Permission denied",
3362 WSAEFAULT , "Bad address",
3363 WSAEINVAL , "Invalid argument",
3364 WSAEMFILE , "Too many open files",
3366 WSAEWOULDBLOCK , "Resource temporarily unavailable",
3367 WSAEINPROGRESS , "Operation now in progress",
3368 WSAEALREADY , "Operation already in progress",
3369 WSAENOTSOCK , "Socket operation on non-socket",
3370 WSAEDESTADDRREQ , "Destination address required",
3371 WSAEMSGSIZE , "Message too long",
3372 WSAEPROTOTYPE , "Protocol wrong type for socket",
3373 WSAENOPROTOOPT , "Bad protocol option",
3374 WSAEPROTONOSUPPORT , "Protocol not supported",
3375 WSAESOCKTNOSUPPORT , "Socket type not supported",
3376 WSAEOPNOTSUPP , "Operation not supported",
3377 WSAEPFNOSUPPORT , "Protocol family not supported",
3378 WSAEAFNOSUPPORT , "Address family not supported by protocol family",
3379 WSAEADDRINUSE , "Address already in use",
3380 WSAEADDRNOTAVAIL , "Cannot assign requested address",
3381 WSAENETDOWN , "Network is down",
3382 WSAENETUNREACH , "Network is unreachable",
3383 WSAENETRESET , "Network dropped connection on reset",
3384 WSAECONNABORTED , "Software caused connection abort",
3385 WSAECONNRESET , "Connection reset by peer",
3386 WSAENOBUFS , "No buffer space available",
3387 WSAEISCONN , "Socket is already connected",
3388 WSAENOTCONN , "Socket is not connected",
3389 WSAESHUTDOWN , "Cannot send after socket shutdown",
3390 WSAETOOMANYREFS , "Too many references", /* not sure */
3391 WSAETIMEDOUT , "Connection timed out",
3392 WSAECONNREFUSED , "Connection refused",
3393 WSAELOOP , "Network loop", /* not sure */
3394 WSAENAMETOOLONG , "Name is too long",
3395 WSAEHOSTDOWN , "Host is down",
3396 WSAEHOSTUNREACH , "No route to host",
3397 WSAENOTEMPTY , "Buffer not empty", /* not sure */
3398 WSAEPROCLIM , "Too many processes",
3399 WSAEUSERS , "Too many users", /* not sure */
3400 WSAEDQUOT , "Double quote in host name", /* really not sure */
3401 WSAESTALE , "Data is stale", /* not sure */
3402 WSAEREMOTE , "Remote error", /* not sure */
3404 WSASYSNOTREADY , "Network subsystem is unavailable",
3405 WSAVERNOTSUPPORTED , "WINSOCK.DLL version out of range",
3406 WSANOTINITIALISED , "Winsock not initialized successfully",
3407 WSAEDISCON , "Graceful shutdown in progress",
3408 #ifdef WSAENOMORE
3409 WSAENOMORE , "No more operations allowed", /* not sure */
3410 WSAECANCELLED , "Operation cancelled", /* not sure */
3411 WSAEINVALIDPROCTABLE , "Invalid procedure table from service provider",
3412 WSAEINVALIDPROVIDER , "Invalid service provider version number",
3413 WSAEPROVIDERFAILEDINIT , "Unable to initialize a service provider",
3414 WSASYSCALLFAILURE , "System call failure",
3415 WSASERVICE_NOT_FOUND , "Service not found", /* not sure */
3416 WSATYPE_NOT_FOUND , "Class type not found",
3417 WSA_E_NO_MORE , "No more resources available", /* really not sure */
3418 WSA_E_CANCELLED , "Operation already cancelled", /* really not sure */
3419 WSAEREFUSED , "Operation refused", /* not sure */
3420 #endif
3422 WSAHOST_NOT_FOUND , "Host not found",
3423 WSATRY_AGAIN , "Authoritative host not found during name lookup",
3424 WSANO_RECOVERY , "Non-recoverable error during name lookup",
3425 WSANO_DATA , "Valid name, no data record of requested type",
3427 -1, NULL
3430 char *
3431 sys_strerror(int error_no)
3433 int i;
3434 static char unknown_msg[40];
3436 if (error_no >= 0 && error_no < sys_nerr)
3437 return sys_errlist[error_no];
3439 for (i = 0; _wsa_errlist[i].errnum >= 0; i++)
3440 if (_wsa_errlist[i].errnum == error_no)
3441 return _wsa_errlist[i].msg;
3443 sprintf(unknown_msg, "Unidentified error: %d", error_no);
3444 return unknown_msg;
3447 /* [andrewi 3-May-96] I've had conflicting results using both methods,
3448 but I believe the method of keeping the socket handle separate (and
3449 insuring it is not inheritable) is the correct one. */
3451 //#define SOCK_REPLACE_HANDLE
3453 #ifdef SOCK_REPLACE_HANDLE
3454 #define SOCK_HANDLE(fd) ((SOCKET) _get_osfhandle (fd))
3455 #else
3456 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
3457 #endif
3459 int socket_to_fd (SOCKET s);
3462 sys_socket(int af, int type, int protocol)
3464 SOCKET s;
3466 if (winsock_lib == NULL)
3468 h_errno = ENETDOWN;
3469 return INVALID_SOCKET;
3472 check_errno ();
3474 /* call the real socket function */
3475 s = pfn_socket (af, type, protocol);
3477 if (s != INVALID_SOCKET)
3478 return socket_to_fd (s);
3480 set_errno ();
3481 return -1;
3484 /* Convert a SOCKET to a file descriptor. */
3486 socket_to_fd (SOCKET s)
3488 int fd;
3489 child_process * cp;
3491 /* Although under NT 3.5 _open_osfhandle will accept a socket
3492 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
3493 that does not work under NT 3.1. However, we can get the same
3494 effect by using a backdoor function to replace an existing
3495 descriptor handle with the one we want. */
3497 /* allocate a file descriptor (with appropriate flags) */
3498 fd = _open ("NUL:", _O_RDWR);
3499 if (fd >= 0)
3501 #ifdef SOCK_REPLACE_HANDLE
3502 /* now replace handle to NUL with our socket handle */
3503 CloseHandle ((HANDLE) _get_osfhandle (fd));
3504 _free_osfhnd (fd);
3505 _set_osfhnd (fd, s);
3506 /* setmode (fd, _O_BINARY); */
3507 #else
3508 /* Make a non-inheritable copy of the socket handle. Note
3509 that it is possible that sockets aren't actually kernel
3510 handles, which appears to be the case on Windows 9x when
3511 the MS Proxy winsock client is installed. */
3513 /* Apparently there is a bug in NT 3.51 with some service
3514 packs, which prevents using DuplicateHandle to make a
3515 socket handle non-inheritable (causes WSACleanup to
3516 hang). The work-around is to use SetHandleInformation
3517 instead if it is available and implemented. */
3518 if (pfn_SetHandleInformation)
3520 pfn_SetHandleInformation ((HANDLE) s, HANDLE_FLAG_INHERIT, 0);
3522 else
3524 HANDLE parent = GetCurrentProcess ();
3525 HANDLE new_s = INVALID_HANDLE_VALUE;
3527 if (DuplicateHandle (parent,
3528 (HANDLE) s,
3529 parent,
3530 &new_s,
3532 FALSE,
3533 DUPLICATE_SAME_ACCESS))
3535 /* It is possible that DuplicateHandle succeeds even
3536 though the socket wasn't really a kernel handle,
3537 because a real handle has the same value. So
3538 test whether the new handle really is a socket. */
3539 long nonblocking = 0;
3540 if (pfn_ioctlsocket ((SOCKET) new_s, FIONBIO, &nonblocking) == 0)
3542 pfn_closesocket (s);
3543 s = (SOCKET) new_s;
3545 else
3547 CloseHandle (new_s);
3552 fd_info[fd].hnd = (HANDLE) s;
3553 #endif
3555 /* set our own internal flags */
3556 fd_info[fd].flags = FILE_SOCKET | FILE_BINARY | FILE_READ | FILE_WRITE;
3558 cp = new_child ();
3559 if (cp)
3561 cp->fd = fd;
3562 cp->status = STATUS_READ_ACKNOWLEDGED;
3564 /* attach child_process to fd_info */
3565 if (fd_info[ fd ].cp != NULL)
3567 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd));
3568 abort ();
3571 fd_info[ fd ].cp = cp;
3573 /* success! */
3574 winsock_inuse++; /* count open sockets */
3575 return fd;
3578 /* clean up */
3579 _close (fd);
3581 pfn_closesocket (s);
3582 h_errno = EMFILE;
3583 return -1;
3588 sys_bind (int s, const struct sockaddr * addr, int namelen)
3590 if (winsock_lib == NULL)
3592 h_errno = ENOTSOCK;
3593 return SOCKET_ERROR;
3596 check_errno ();
3597 if (fd_info[s].flags & FILE_SOCKET)
3599 int rc = pfn_bind (SOCK_HANDLE (s), addr, namelen);
3600 if (rc == SOCKET_ERROR)
3601 set_errno ();
3602 return rc;
3604 h_errno = ENOTSOCK;
3605 return SOCKET_ERROR;
3610 sys_connect (int s, const struct sockaddr * name, int namelen)
3612 if (winsock_lib == NULL)
3614 h_errno = ENOTSOCK;
3615 return SOCKET_ERROR;
3618 check_errno ();
3619 if (fd_info[s].flags & FILE_SOCKET)
3621 int rc = pfn_connect (SOCK_HANDLE (s), name, namelen);
3622 if (rc == SOCKET_ERROR)
3623 set_errno ();
3624 return rc;
3626 h_errno = ENOTSOCK;
3627 return SOCKET_ERROR;
3630 u_short
3631 sys_htons (u_short hostshort)
3633 return (winsock_lib != NULL) ?
3634 pfn_htons (hostshort) : hostshort;
3637 u_short
3638 sys_ntohs (u_short netshort)
3640 return (winsock_lib != NULL) ?
3641 pfn_ntohs (netshort) : netshort;
3644 unsigned long
3645 sys_inet_addr (const char * cp)
3647 return (winsock_lib != NULL) ?
3648 pfn_inet_addr (cp) : INADDR_NONE;
3652 sys_gethostname (char * name, int namelen)
3654 if (winsock_lib != NULL)
3655 return pfn_gethostname (name, namelen);
3657 if (namelen > MAX_COMPUTERNAME_LENGTH)
3658 return !GetComputerName (name, (DWORD *)&namelen);
3660 h_errno = EFAULT;
3661 return SOCKET_ERROR;
3664 struct hostent *
3665 sys_gethostbyname(const char * name)
3667 struct hostent * host;
3669 if (winsock_lib == NULL)
3671 h_errno = ENETDOWN;
3672 return NULL;
3675 check_errno ();
3676 host = pfn_gethostbyname (name);
3677 if (!host)
3678 set_errno ();
3679 return host;
3682 struct servent *
3683 sys_getservbyname(const char * name, const char * proto)
3685 struct servent * serv;
3687 if (winsock_lib == NULL)
3689 h_errno = ENETDOWN;
3690 return NULL;
3693 check_errno ();
3694 serv = pfn_getservbyname (name, proto);
3695 if (!serv)
3696 set_errno ();
3697 return serv;
3701 sys_getpeername (int s, struct sockaddr *addr, int * namelen)
3703 if (winsock_lib == NULL)
3705 h_errno = ENETDOWN;
3706 return SOCKET_ERROR;
3709 check_errno ();
3710 if (fd_info[s].flags & FILE_SOCKET)
3712 int rc = pfn_getpeername (SOCK_HANDLE (s), addr, namelen);
3713 if (rc == SOCKET_ERROR)
3714 set_errno ();
3715 return rc;
3717 h_errno = ENOTSOCK;
3718 return SOCKET_ERROR;
3723 sys_shutdown (int s, int how)
3725 if (winsock_lib == NULL)
3727 h_errno = ENETDOWN;
3728 return SOCKET_ERROR;
3731 check_errno ();
3732 if (fd_info[s].flags & FILE_SOCKET)
3734 int rc = pfn_shutdown (SOCK_HANDLE (s), how);
3735 if (rc == SOCKET_ERROR)
3736 set_errno ();
3737 return rc;
3739 h_errno = ENOTSOCK;
3740 return SOCKET_ERROR;
3744 sys_setsockopt (int s, int level, int optname, const void * optval, int optlen)
3746 if (winsock_lib == NULL)
3748 h_errno = ENETDOWN;
3749 return SOCKET_ERROR;
3752 check_errno ();
3753 if (fd_info[s].flags & FILE_SOCKET)
3755 int rc = pfn_setsockopt (SOCK_HANDLE (s), level, optname,
3756 (const char *)optval, optlen);
3757 if (rc == SOCKET_ERROR)
3758 set_errno ();
3759 return rc;
3761 h_errno = ENOTSOCK;
3762 return SOCKET_ERROR;
3766 sys_listen (int s, int backlog)
3768 if (winsock_lib == NULL)
3770 h_errno = ENETDOWN;
3771 return SOCKET_ERROR;
3774 check_errno ();
3775 if (fd_info[s].flags & FILE_SOCKET)
3777 int rc = pfn_listen (SOCK_HANDLE (s), backlog);
3778 if (rc == SOCKET_ERROR)
3779 set_errno ();
3780 else
3781 fd_info[s].flags |= FILE_LISTEN;
3782 return rc;
3784 h_errno = ENOTSOCK;
3785 return SOCKET_ERROR;
3789 sys_getsockname (int s, struct sockaddr * name, int * namelen)
3791 if (winsock_lib == NULL)
3793 h_errno = ENETDOWN;
3794 return SOCKET_ERROR;
3797 check_errno ();
3798 if (fd_info[s].flags & FILE_SOCKET)
3800 int rc = pfn_getsockname (SOCK_HANDLE (s), name, namelen);
3801 if (rc == SOCKET_ERROR)
3802 set_errno ();
3803 return rc;
3805 h_errno = ENOTSOCK;
3806 return SOCKET_ERROR;
3810 sys_accept (int s, struct sockaddr * addr, int * addrlen)
3812 if (winsock_lib == NULL)
3814 h_errno = ENETDOWN;
3815 return -1;
3818 check_errno ();
3819 if (fd_info[s].flags & FILE_LISTEN)
3821 SOCKET t = pfn_accept (SOCK_HANDLE (s), addr, addrlen);
3822 int fd = -1;
3823 if (t == INVALID_SOCKET)
3824 set_errno ();
3825 else
3826 fd = socket_to_fd (t);
3828 fd_info[s].cp->status = STATUS_READ_ACKNOWLEDGED;
3829 ResetEvent (fd_info[s].cp->char_avail);
3830 return fd;
3832 h_errno = ENOTSOCK;
3833 return -1;
3837 sys_recvfrom (int s, char * buf, int len, int flags,
3838 struct sockaddr * from, int * fromlen)
3840 if (winsock_lib == NULL)
3842 h_errno = ENETDOWN;
3843 return SOCKET_ERROR;
3846 check_errno ();
3847 if (fd_info[s].flags & FILE_SOCKET)
3849 int rc = pfn_recvfrom (SOCK_HANDLE (s), buf, len, flags, from, fromlen);
3850 if (rc == SOCKET_ERROR)
3851 set_errno ();
3852 return rc;
3854 h_errno = ENOTSOCK;
3855 return SOCKET_ERROR;
3859 sys_sendto (int s, const char * buf, int len, int flags,
3860 const struct sockaddr * to, int tolen)
3862 if (winsock_lib == NULL)
3864 h_errno = ENETDOWN;
3865 return SOCKET_ERROR;
3868 check_errno ();
3869 if (fd_info[s].flags & FILE_SOCKET)
3871 int rc = pfn_sendto (SOCK_HANDLE (s), buf, len, flags, to, tolen);
3872 if (rc == SOCKET_ERROR)
3873 set_errno ();
3874 return rc;
3876 h_errno = ENOTSOCK;
3877 return SOCKET_ERROR;
3880 /* Windows does not have an fcntl function. Provide an implementation
3881 solely for making sockets non-blocking. */
3883 fcntl (int s, int cmd, int options)
3885 if (winsock_lib == NULL)
3887 h_errno = ENETDOWN;
3888 return -1;
3891 check_errno ();
3892 if (fd_info[s].flags & FILE_SOCKET)
3894 if (cmd == F_SETFL && options == O_NDELAY)
3896 unsigned long nblock = 1;
3897 int rc = pfn_ioctlsocket (SOCK_HANDLE (s), FIONBIO, &nblock);
3898 if (rc == SOCKET_ERROR)
3899 set_errno();
3900 /* Keep track of the fact that we set this to non-blocking. */
3901 fd_info[s].flags |= FILE_NDELAY;
3902 return rc;
3904 else
3906 h_errno = EINVAL;
3907 return SOCKET_ERROR;
3910 h_errno = ENOTSOCK;
3911 return SOCKET_ERROR;
3914 #endif /* HAVE_SOCKETS */
3917 /* Shadow main io functions: we need to handle pipes and sockets more
3918 intelligently, and implement non-blocking mode as well. */
3921 sys_close (int fd)
3923 int rc;
3925 if (fd < 0)
3927 errno = EBADF;
3928 return -1;
3931 if (fd < MAXDESC && fd_info[fd].cp)
3933 child_process * cp = fd_info[fd].cp;
3935 fd_info[fd].cp = NULL;
3937 if (CHILD_ACTIVE (cp))
3939 /* if last descriptor to active child_process then cleanup */
3940 int i;
3941 for (i = 0; i < MAXDESC; i++)
3943 if (i == fd)
3944 continue;
3945 if (fd_info[i].cp == cp)
3946 break;
3948 if (i == MAXDESC)
3950 #ifdef HAVE_SOCKETS
3951 if (fd_info[fd].flags & FILE_SOCKET)
3953 #ifndef SOCK_REPLACE_HANDLE
3954 if (winsock_lib == NULL) abort ();
3956 pfn_shutdown (SOCK_HANDLE (fd), 2);
3957 rc = pfn_closesocket (SOCK_HANDLE (fd));
3958 #endif
3959 winsock_inuse--; /* count open sockets */
3961 #endif
3962 delete_child (cp);
3967 /* Note that sockets do not need special treatment here (at least on
3968 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
3969 closesocket is equivalent to CloseHandle, which is to be expected
3970 because socket handles are fully fledged kernel handles. */
3971 rc = _close (fd);
3973 if (rc == 0 && fd < MAXDESC)
3974 fd_info[fd].flags = 0;
3976 return rc;
3980 sys_dup (int fd)
3982 int new_fd;
3984 new_fd = _dup (fd);
3985 if (new_fd >= 0 && new_fd < MAXDESC)
3987 /* duplicate our internal info as well */
3988 fd_info[new_fd] = fd_info[fd];
3990 return new_fd;
3995 sys_dup2 (int src, int dst)
3997 int rc;
3999 if (dst < 0 || dst >= MAXDESC)
4001 errno = EBADF;
4002 return -1;
4005 /* make sure we close the destination first if it's a pipe or socket */
4006 if (src != dst && fd_info[dst].flags != 0)
4007 sys_close (dst);
4009 rc = _dup2 (src, dst);
4010 if (rc == 0)
4012 /* duplicate our internal info as well */
4013 fd_info[dst] = fd_info[src];
4015 return rc;
4018 /* Unix pipe() has only one arg */
4020 sys_pipe (int * phandles)
4022 int rc;
4023 unsigned flags;
4025 /* make pipe handles non-inheritable; when we spawn a child, we
4026 replace the relevant handle with an inheritable one. Also put
4027 pipes into binary mode; we will do text mode translation ourselves
4028 if required. */
4029 rc = _pipe (phandles, 0, _O_NOINHERIT | _O_BINARY);
4031 if (rc == 0)
4033 /* Protect against overflow, since Windows can open more handles than
4034 our fd_info array has room for. */
4035 if (phandles[0] >= MAXDESC || phandles[1] >= MAXDESC)
4037 _close (phandles[0]);
4038 _close (phandles[1]);
4039 rc = -1;
4041 else
4043 flags = FILE_PIPE | FILE_READ | FILE_BINARY;
4044 fd_info[phandles[0]].flags = flags;
4046 flags = FILE_PIPE | FILE_WRITE | FILE_BINARY;
4047 fd_info[phandles[1]].flags = flags;
4051 return rc;
4054 /* From ntproc.c */
4055 extern int w32_pipe_read_delay;
4057 /* Function to do blocking read of one byte, needed to implement
4058 select. It is only allowed on sockets and pipes. */
4060 _sys_read_ahead (int fd)
4062 child_process * cp;
4063 int rc;
4065 if (fd < 0 || fd >= MAXDESC)
4066 return STATUS_READ_ERROR;
4068 cp = fd_info[fd].cp;
4070 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
4071 return STATUS_READ_ERROR;
4073 if ((fd_info[fd].flags & (FILE_PIPE | FILE_SERIAL | FILE_SOCKET)) == 0
4074 || (fd_info[fd].flags & FILE_READ) == 0)
4076 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd));
4077 abort ();
4080 cp->status = STATUS_READ_IN_PROGRESS;
4082 if (fd_info[fd].flags & FILE_PIPE)
4084 rc = _read (fd, &cp->chr, sizeof (char));
4086 /* Give subprocess time to buffer some more output for us before
4087 reporting that input is available; we need this because Windows 95
4088 connects DOS programs to pipes by making the pipe appear to be
4089 the normal console stdout - as a result most DOS programs will
4090 write to stdout without buffering, ie. one character at a
4091 time. Even some W32 programs do this - "dir" in a command
4092 shell on NT is very slow if we don't do this. */
4093 if (rc > 0)
4095 int wait = w32_pipe_read_delay;
4097 if (wait > 0)
4098 Sleep (wait);
4099 else if (wait < 0)
4100 while (++wait <= 0)
4101 /* Yield remainder of our time slice, effectively giving a
4102 temporary priority boost to the child process. */
4103 Sleep (0);
4106 else if (fd_info[fd].flags & FILE_SERIAL)
4108 HANDLE hnd = fd_info[fd].hnd;
4109 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
4110 COMMTIMEOUTS ct;
4112 /* Configure timeouts for blocking read. */
4113 if (!GetCommTimeouts (hnd, &ct))
4114 return STATUS_READ_ERROR;
4115 ct.ReadIntervalTimeout = 0;
4116 ct.ReadTotalTimeoutMultiplier = 0;
4117 ct.ReadTotalTimeoutConstant = 0;
4118 if (!SetCommTimeouts (hnd, &ct))
4119 return STATUS_READ_ERROR;
4121 if (!ReadFile (hnd, &cp->chr, sizeof (char), (DWORD*) &rc, ovl))
4123 if (GetLastError () != ERROR_IO_PENDING)
4124 return STATUS_READ_ERROR;
4125 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
4126 return STATUS_READ_ERROR;
4129 #ifdef HAVE_SOCKETS
4130 else if (fd_info[fd].flags & FILE_SOCKET)
4132 unsigned long nblock = 0;
4133 /* We always want this to block, so temporarily disable NDELAY. */
4134 if (fd_info[fd].flags & FILE_NDELAY)
4135 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
4137 rc = pfn_recv (SOCK_HANDLE (fd), &cp->chr, sizeof (char), 0);
4139 if (fd_info[fd].flags & FILE_NDELAY)
4141 nblock = 1;
4142 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
4145 #endif
4147 if (rc == sizeof (char))
4148 cp->status = STATUS_READ_SUCCEEDED;
4149 else
4150 cp->status = STATUS_READ_FAILED;
4152 return cp->status;
4156 _sys_wait_accept (int fd)
4158 HANDLE hEv;
4159 child_process * cp;
4160 int rc;
4162 if (fd < 0 || fd >= MAXDESC)
4163 return STATUS_READ_ERROR;
4165 cp = fd_info[fd].cp;
4167 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
4168 return STATUS_READ_ERROR;
4170 cp->status = STATUS_READ_FAILED;
4172 hEv = pfn_WSACreateEvent ();
4173 rc = pfn_WSAEventSelect (SOCK_HANDLE (fd), hEv, FD_ACCEPT);
4174 if (rc != SOCKET_ERROR)
4176 rc = WaitForSingleObject (hEv, INFINITE);
4177 pfn_WSAEventSelect (SOCK_HANDLE (fd), NULL, 0);
4178 if (rc == WAIT_OBJECT_0)
4179 cp->status = STATUS_READ_SUCCEEDED;
4181 pfn_WSACloseEvent (hEv);
4183 return cp->status;
4187 sys_read (int fd, char * buffer, unsigned int count)
4189 int nchars;
4190 int to_read;
4191 DWORD waiting;
4192 char * orig_buffer = buffer;
4194 if (fd < 0)
4196 errno = EBADF;
4197 return -1;
4200 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
4202 child_process *cp = fd_info[fd].cp;
4204 if ((fd_info[fd].flags & FILE_READ) == 0)
4206 errno = EBADF;
4207 return -1;
4210 nchars = 0;
4212 /* re-read CR carried over from last read */
4213 if (fd_info[fd].flags & FILE_LAST_CR)
4215 if (fd_info[fd].flags & FILE_BINARY) abort ();
4216 *buffer++ = 0x0d;
4217 count--;
4218 nchars++;
4219 fd_info[fd].flags &= ~FILE_LAST_CR;
4222 /* presence of a child_process structure means we are operating in
4223 non-blocking mode - otherwise we just call _read directly.
4224 Note that the child_process structure might be missing because
4225 reap_subprocess has been called; in this case the pipe is
4226 already broken, so calling _read on it is okay. */
4227 if (cp)
4229 int current_status = cp->status;
4231 switch (current_status)
4233 case STATUS_READ_FAILED:
4234 case STATUS_READ_ERROR:
4235 /* report normal EOF if nothing in buffer */
4236 if (nchars <= 0)
4237 fd_info[fd].flags |= FILE_AT_EOF;
4238 return nchars;
4240 case STATUS_READ_READY:
4241 case STATUS_READ_IN_PROGRESS:
4242 DebPrint (("sys_read called when read is in progress\n"));
4243 errno = EWOULDBLOCK;
4244 return -1;
4246 case STATUS_READ_SUCCEEDED:
4247 /* consume read-ahead char */
4248 *buffer++ = cp->chr;
4249 count--;
4250 nchars++;
4251 cp->status = STATUS_READ_ACKNOWLEDGED;
4252 ResetEvent (cp->char_avail);
4254 case STATUS_READ_ACKNOWLEDGED:
4255 break;
4257 default:
4258 DebPrint (("sys_read: bad status %d\n", current_status));
4259 errno = EBADF;
4260 return -1;
4263 if (fd_info[fd].flags & FILE_PIPE)
4265 PeekNamedPipe ((HANDLE) _get_osfhandle (fd), NULL, 0, NULL, &waiting, NULL);
4266 to_read = min (waiting, (DWORD) count);
4268 if (to_read > 0)
4269 nchars += _read (fd, buffer, to_read);
4271 else if (fd_info[fd].flags & FILE_SERIAL)
4273 HANDLE hnd = fd_info[fd].hnd;
4274 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
4275 DWORD err = 0;
4276 int rc = 0;
4277 COMMTIMEOUTS ct;
4279 if (count > 0)
4281 /* Configure timeouts for non-blocking read. */
4282 if (!GetCommTimeouts (hnd, &ct))
4284 errno = EIO;
4285 return -1;
4287 ct.ReadIntervalTimeout = MAXDWORD;
4288 ct.ReadTotalTimeoutMultiplier = 0;
4289 ct.ReadTotalTimeoutConstant = 0;
4290 if (!SetCommTimeouts (hnd, &ct))
4292 errno = EIO;
4293 return -1;
4296 if (!ResetEvent (ovl->hEvent))
4298 errno = EIO;
4299 return -1;
4301 if (!ReadFile (hnd, buffer, count, (DWORD*) &rc, ovl))
4303 if (GetLastError () != ERROR_IO_PENDING)
4305 errno = EIO;
4306 return -1;
4308 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
4310 errno = EIO;
4311 return -1;
4314 nchars += rc;
4317 #ifdef HAVE_SOCKETS
4318 else /* FILE_SOCKET */
4320 if (winsock_lib == NULL) abort ();
4322 /* do the equivalent of a non-blocking read */
4323 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONREAD, &waiting);
4324 if (waiting == 0 && nchars == 0)
4326 h_errno = errno = EWOULDBLOCK;
4327 return -1;
4330 if (waiting)
4332 /* always use binary mode for sockets */
4333 int res = pfn_recv (SOCK_HANDLE (fd), buffer, count, 0);
4334 if (res == SOCKET_ERROR)
4336 DebPrint(("sys_read.recv failed with error %d on socket %ld\n",
4337 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
4338 set_errno ();
4339 return -1;
4341 nchars += res;
4344 #endif
4346 else
4348 int nread = _read (fd, buffer, count);
4349 if (nread >= 0)
4350 nchars += nread;
4351 else if (nchars == 0)
4352 nchars = nread;
4355 if (nchars <= 0)
4356 fd_info[fd].flags |= FILE_AT_EOF;
4357 /* Perform text mode translation if required. */
4358 else if ((fd_info[fd].flags & FILE_BINARY) == 0)
4360 nchars = crlf_to_lf (nchars, orig_buffer);
4361 /* If buffer contains only CR, return that. To be absolutely
4362 sure we should attempt to read the next char, but in
4363 practice a CR to be followed by LF would not appear by
4364 itself in the buffer. */
4365 if (nchars > 1 && orig_buffer[nchars - 1] == 0x0d)
4367 fd_info[fd].flags |= FILE_LAST_CR;
4368 nchars--;
4372 else
4373 nchars = _read (fd, buffer, count);
4375 return nchars;
4378 /* From w32xfns.c */
4379 extern HANDLE interrupt_handle;
4381 /* For now, don't bother with a non-blocking mode */
4383 sys_write (int fd, const void * buffer, unsigned int count)
4385 int nchars;
4387 if (fd < 0)
4389 errno = EBADF;
4390 return -1;
4393 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
4395 if ((fd_info[fd].flags & FILE_WRITE) == 0)
4397 errno = EBADF;
4398 return -1;
4401 /* Perform text mode translation if required. */
4402 if ((fd_info[fd].flags & FILE_BINARY) == 0)
4404 char * tmpbuf = alloca (count * 2);
4405 unsigned char * src = (void *)buffer;
4406 unsigned char * dst = tmpbuf;
4407 int nbytes = count;
4409 while (1)
4411 unsigned char *next;
4412 /* copy next line or remaining bytes */
4413 next = _memccpy (dst, src, '\n', nbytes);
4414 if (next)
4416 /* copied one line ending with '\n' */
4417 int copied = next - dst;
4418 nbytes -= copied;
4419 src += copied;
4420 /* insert '\r' before '\n' */
4421 next[-1] = '\r';
4422 next[0] = '\n';
4423 dst = next + 1;
4424 count++;
4426 else
4427 /* copied remaining partial line -> now finished */
4428 break;
4430 buffer = tmpbuf;
4434 if (fd < MAXDESC && fd_info[fd].flags & FILE_SERIAL)
4436 HANDLE hnd = (HANDLE) _get_osfhandle (fd);
4437 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_write;
4438 HANDLE wait_hnd[2] = { interrupt_handle, ovl->hEvent };
4439 DWORD active = 0;
4441 if (!WriteFile (hnd, buffer, count, (DWORD*) &nchars, ovl))
4443 if (GetLastError () != ERROR_IO_PENDING)
4445 errno = EIO;
4446 return -1;
4448 if (detect_input_pending ())
4449 active = MsgWaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE,
4450 QS_ALLINPUT);
4451 else
4452 active = WaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE);
4453 if (active == WAIT_OBJECT_0)
4454 { /* User pressed C-g, cancel write, then leave. Don't bother
4455 cleaning up as we may only get stuck in buggy drivers. */
4456 PurgeComm (hnd, PURGE_TXABORT | PURGE_TXCLEAR);
4457 CancelIo (hnd);
4458 errno = EIO;
4459 return -1;
4461 if (active == WAIT_OBJECT_0 + 1
4462 && !GetOverlappedResult (hnd, ovl, (DWORD*) &nchars, TRUE))
4464 errno = EIO;
4465 return -1;
4469 else
4470 #ifdef HAVE_SOCKETS
4471 if (fd < MAXDESC && fd_info[fd].flags & FILE_SOCKET)
4473 unsigned long nblock = 0;
4474 if (winsock_lib == NULL) abort ();
4476 /* TODO: implement select() properly so non-blocking I/O works. */
4477 /* For now, make sure the write blocks. */
4478 if (fd_info[fd].flags & FILE_NDELAY)
4479 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
4481 nchars = pfn_send (SOCK_HANDLE (fd), buffer, count, 0);
4483 /* Set the socket back to non-blocking if it was before,
4484 for other operations that support it. */
4485 if (fd_info[fd].flags & FILE_NDELAY)
4487 nblock = 1;
4488 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
4491 if (nchars == SOCKET_ERROR)
4493 DebPrint(("sys_write.send failed with error %d on socket %ld\n",
4494 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
4495 set_errno ();
4498 else
4499 #endif
4500 nchars = _write (fd, buffer, count);
4502 return nchars;
4505 static void
4506 check_windows_init_file ()
4508 extern int noninteractive, inhibit_window_system;
4510 /* A common indication that Emacs is not installed properly is when
4511 it cannot find the Windows installation file. If this file does
4512 not exist in the expected place, tell the user. */
4514 if (!noninteractive && !inhibit_window_system)
4516 extern Lisp_Object Vwindow_system, Vload_path, Qfile_exists_p;
4517 Lisp_Object objs[2];
4518 Lisp_Object full_load_path;
4519 Lisp_Object init_file;
4520 int fd;
4522 objs[0] = Vload_path;
4523 objs[1] = decode_env_path (0, (getenv ("EMACSLOADPATH")));
4524 full_load_path = Fappend (2, objs);
4525 init_file = build_string ("term/w32-win");
4526 fd = openp (full_load_path, init_file, Fget_load_suffixes (), NULL, Qnil);
4527 if (fd < 0)
4529 Lisp_Object load_path_print = Fprin1_to_string (full_load_path, Qnil);
4530 char *init_file_name = SDATA (init_file);
4531 char *load_path = SDATA (load_path_print);
4532 char *buffer = alloca (1024
4533 + strlen (init_file_name)
4534 + strlen (load_path));
4536 sprintf (buffer,
4537 "The Emacs Windows initialization file \"%s.el\" "
4538 "could not be found in your Emacs installation. "
4539 "Emacs checked the following directories for this file:\n"
4540 "\n%s\n\n"
4541 "When Emacs cannot find this file, it usually means that it "
4542 "was not installed properly, or its distribution file was "
4543 "not unpacked properly.\nSee the README.W32 file in the "
4544 "top-level Emacs directory for more information.",
4545 init_file_name, load_path);
4546 MessageBox (NULL,
4547 buffer,
4548 "Emacs Abort Dialog",
4549 MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
4550 /* Use the low-level Emacs abort. */
4551 #undef abort
4552 abort ();
4554 else
4556 _close (fd);
4561 void
4562 term_ntproc ()
4564 #ifdef HAVE_SOCKETS
4565 /* shutdown the socket interface if necessary */
4566 term_winsock ();
4567 #endif
4569 term_w32select ();
4572 void
4573 init_ntproc ()
4575 #ifdef HAVE_SOCKETS
4576 /* Initialise the socket interface now if available and requested by
4577 the user by defining PRELOAD_WINSOCK; otherwise loading will be
4578 delayed until open-network-stream is called (w32-has-winsock can
4579 also be used to dynamically load or reload winsock).
4581 Conveniently, init_environment is called before us, so
4582 PRELOAD_WINSOCK can be set in the registry. */
4584 /* Always initialize this correctly. */
4585 winsock_lib = NULL;
4587 if (getenv ("PRELOAD_WINSOCK") != NULL)
4588 init_winsock (TRUE);
4589 #endif
4591 /* Initial preparation for subprocess support: replace our standard
4592 handles with non-inheritable versions. */
4594 HANDLE parent;
4595 HANDLE stdin_save = INVALID_HANDLE_VALUE;
4596 HANDLE stdout_save = INVALID_HANDLE_VALUE;
4597 HANDLE stderr_save = INVALID_HANDLE_VALUE;
4599 parent = GetCurrentProcess ();
4601 /* ignore errors when duplicating and closing; typically the
4602 handles will be invalid when running as a gui program. */
4603 DuplicateHandle (parent,
4604 GetStdHandle (STD_INPUT_HANDLE),
4605 parent,
4606 &stdin_save,
4608 FALSE,
4609 DUPLICATE_SAME_ACCESS);
4611 DuplicateHandle (parent,
4612 GetStdHandle (STD_OUTPUT_HANDLE),
4613 parent,
4614 &stdout_save,
4616 FALSE,
4617 DUPLICATE_SAME_ACCESS);
4619 DuplicateHandle (parent,
4620 GetStdHandle (STD_ERROR_HANDLE),
4621 parent,
4622 &stderr_save,
4624 FALSE,
4625 DUPLICATE_SAME_ACCESS);
4627 fclose (stdin);
4628 fclose (stdout);
4629 fclose (stderr);
4631 if (stdin_save != INVALID_HANDLE_VALUE)
4632 _open_osfhandle ((long) stdin_save, O_TEXT);
4633 else
4634 _open ("nul", O_TEXT | O_NOINHERIT | O_RDONLY);
4635 _fdopen (0, "r");
4637 if (stdout_save != INVALID_HANDLE_VALUE)
4638 _open_osfhandle ((long) stdout_save, O_TEXT);
4639 else
4640 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
4641 _fdopen (1, "w");
4643 if (stderr_save != INVALID_HANDLE_VALUE)
4644 _open_osfhandle ((long) stderr_save, O_TEXT);
4645 else
4646 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
4647 _fdopen (2, "w");
4650 /* unfortunately, atexit depends on implementation of malloc */
4651 /* atexit (term_ntproc); */
4652 signal (SIGABRT, term_ntproc);
4654 /* determine which drives are fixed, for GetCachedVolumeInformation */
4656 /* GetDriveType must have trailing backslash. */
4657 char drive[] = "A:\\";
4659 /* Loop over all possible drive letters */
4660 while (*drive <= 'Z')
4662 /* Record if this drive letter refers to a fixed drive. */
4663 fixed_drives[DRIVE_INDEX (*drive)] =
4664 (GetDriveType (drive) == DRIVE_FIXED);
4666 (*drive)++;
4669 /* Reset the volume info cache. */
4670 volume_cache = NULL;
4673 /* Check to see if Emacs has been installed correctly. */
4674 check_windows_init_file ();
4678 shutdown_handler ensures that buffers' autosave files are
4679 up to date when the user logs off, or the system shuts down.
4681 BOOL WINAPI shutdown_handler(DWORD type)
4683 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
4684 if (type == CTRL_CLOSE_EVENT /* User closes console window. */
4685 || type == CTRL_LOGOFF_EVENT /* User logs off. */
4686 || type == CTRL_SHUTDOWN_EVENT) /* User shutsdown. */
4688 /* Shut down cleanly, making sure autosave files are up to date. */
4689 shut_down_emacs (0, 0, Qnil);
4692 /* Allow other handlers to handle this signal. */
4693 return FALSE;
4697 globals_of_w32 is used to initialize those global variables that
4698 must always be initialized on startup even when the global variable
4699 initialized is non zero (see the function main in emacs.c).
4701 void
4702 globals_of_w32 ()
4704 HMODULE kernel32 = GetModuleHandle ("kernel32.dll");
4706 get_process_times_fn = (GetProcessTimes_Proc)
4707 GetProcAddress (kernel32, "GetProcessTimes");
4709 g_b_init_is_windows_9x = 0;
4710 g_b_init_open_process_token = 0;
4711 g_b_init_get_token_information = 0;
4712 g_b_init_lookup_account_sid = 0;
4713 g_b_init_get_sid_identifier_authority = 0;
4714 g_b_init_get_sid_sub_authority = 0;
4715 g_b_init_get_sid_sub_authority_count = 0;
4716 g_b_init_get_file_security = 0;
4717 g_b_init_get_security_descriptor_owner = 0;
4718 g_b_init_get_security_descriptor_group = 0;
4719 g_b_init_is_valid_sid = 0;
4720 /* The following sets a handler for shutdown notifications for
4721 console apps. This actually applies to Emacs in both console and
4722 GUI modes, since we had to fool windows into thinking emacs is a
4723 console application to get console mode to work. */
4724 SetConsoleCtrlHandler(shutdown_handler, TRUE);
4726 /* "None" is the default group name on standalone workstations. */
4727 strcpy (dflt_group_name, "None");
4730 /* For make-serial-process */
4731 int serial_open (char *port)
4733 HANDLE hnd;
4734 child_process *cp;
4735 int fd = -1;
4737 hnd = CreateFile (port, GENERIC_READ | GENERIC_WRITE, 0, 0,
4738 OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
4739 if (hnd == INVALID_HANDLE_VALUE)
4740 error ("Could not open %s", port);
4741 fd = (int) _open_osfhandle ((int) hnd, 0);
4742 if (fd == -1)
4743 error ("Could not open %s", port);
4745 cp = new_child ();
4746 if (!cp)
4747 error ("Could not create child process");
4748 cp->fd = fd;
4749 cp->status = STATUS_READ_ACKNOWLEDGED;
4750 fd_info[ fd ].hnd = hnd;
4751 fd_info[ fd ].flags |=
4752 FILE_READ | FILE_WRITE | FILE_BINARY | FILE_SERIAL;
4753 if (fd_info[ fd ].cp != NULL)
4755 error ("fd_info[fd = %d] is already in use", fd);
4757 fd_info[ fd ].cp = cp;
4758 cp->ovl_read.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
4759 if (cp->ovl_read.hEvent == NULL)
4760 error ("Could not create read event");
4761 cp->ovl_write.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
4762 if (cp->ovl_write.hEvent == NULL)
4763 error ("Could not create write event");
4765 return fd;
4768 /* For serial-process-configure */
4769 void
4770 serial_configure (struct Lisp_Process *p,
4771 Lisp_Object contact)
4773 Lisp_Object childp2 = Qnil;
4774 Lisp_Object tem = Qnil;
4775 HANDLE hnd;
4776 DCB dcb;
4777 COMMTIMEOUTS ct;
4778 char summary[4] = "???"; /* This usually becomes "8N1". */
4780 if ((fd_info[ p->outfd ].flags & FILE_SERIAL) == 0)
4781 error ("Not a serial process");
4782 hnd = fd_info[ p->outfd ].hnd;
4784 childp2 = Fcopy_sequence (p->childp);
4786 /* Initialize timeouts for blocking read and blocking write. */
4787 if (!GetCommTimeouts (hnd, &ct))
4788 error ("GetCommTimeouts() failed");
4789 ct.ReadIntervalTimeout = 0;
4790 ct.ReadTotalTimeoutMultiplier = 0;
4791 ct.ReadTotalTimeoutConstant = 0;
4792 ct.WriteTotalTimeoutMultiplier = 0;
4793 ct.WriteTotalTimeoutConstant = 0;
4794 if (!SetCommTimeouts (hnd, &ct))
4795 error ("SetCommTimeouts() failed");
4796 /* Read port attributes and prepare default configuration. */
4797 memset (&dcb, 0, sizeof (dcb));
4798 dcb.DCBlength = sizeof (DCB);
4799 if (!GetCommState (hnd, &dcb))
4800 error ("GetCommState() failed");
4801 dcb.fBinary = TRUE;
4802 dcb.fNull = FALSE;
4803 dcb.fAbortOnError = FALSE;
4804 /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
4805 dcb.ErrorChar = 0;
4806 dcb.EofChar = 0;
4807 dcb.EvtChar = 0;
4809 /* Configure speed. */
4810 if (!NILP (Fplist_member (contact, QCspeed)))
4811 tem = Fplist_get (contact, QCspeed);
4812 else
4813 tem = Fplist_get (p->childp, QCspeed);
4814 CHECK_NUMBER (tem);
4815 dcb.BaudRate = XINT (tem);
4816 childp2 = Fplist_put (childp2, QCspeed, tem);
4818 /* Configure bytesize. */
4819 if (!NILP (Fplist_member (contact, QCbytesize)))
4820 tem = Fplist_get (contact, QCbytesize);
4821 else
4822 tem = Fplist_get (p->childp, QCbytesize);
4823 if (NILP (tem))
4824 tem = make_number (8);
4825 CHECK_NUMBER (tem);
4826 if (XINT (tem) != 7 && XINT (tem) != 8)
4827 error (":bytesize must be nil (8), 7, or 8");
4828 dcb.ByteSize = XINT (tem);
4829 summary[0] = XINT (tem) + '0';
4830 childp2 = Fplist_put (childp2, QCbytesize, tem);
4832 /* Configure parity. */
4833 if (!NILP (Fplist_member (contact, QCparity)))
4834 tem = Fplist_get (contact, QCparity);
4835 else
4836 tem = Fplist_get (p->childp, QCparity);
4837 if (!NILP (tem) && !EQ (tem, Qeven) && !EQ (tem, Qodd))
4838 error (":parity must be nil (no parity), `even', or `odd'");
4839 dcb.fParity = FALSE;
4840 dcb.Parity = NOPARITY;
4841 dcb.fErrorChar = FALSE;
4842 if (NILP (tem))
4844 summary[1] = 'N';
4846 else if (EQ (tem, Qeven))
4848 summary[1] = 'E';
4849 dcb.fParity = TRUE;
4850 dcb.Parity = EVENPARITY;
4851 dcb.fErrorChar = TRUE;
4853 else if (EQ (tem, Qodd))
4855 summary[1] = 'O';
4856 dcb.fParity = TRUE;
4857 dcb.Parity = ODDPARITY;
4858 dcb.fErrorChar = TRUE;
4860 childp2 = Fplist_put (childp2, QCparity, tem);
4862 /* Configure stopbits. */
4863 if (!NILP (Fplist_member (contact, QCstopbits)))
4864 tem = Fplist_get (contact, QCstopbits);
4865 else
4866 tem = Fplist_get (p->childp, QCstopbits);
4867 if (NILP (tem))
4868 tem = make_number (1);
4869 CHECK_NUMBER (tem);
4870 if (XINT (tem) != 1 && XINT (tem) != 2)
4871 error (":stopbits must be nil (1 stopbit), 1, or 2");
4872 summary[2] = XINT (tem) + '0';
4873 if (XINT (tem) == 1)
4874 dcb.StopBits = ONESTOPBIT;
4875 else if (XINT (tem) == 2)
4876 dcb.StopBits = TWOSTOPBITS;
4877 childp2 = Fplist_put (childp2, QCstopbits, tem);
4879 /* Configure flowcontrol. */
4880 if (!NILP (Fplist_member (contact, QCflowcontrol)))
4881 tem = Fplist_get (contact, QCflowcontrol);
4882 else
4883 tem = Fplist_get (p->childp, QCflowcontrol);
4884 if (!NILP (tem) && !EQ (tem, Qhw) && !EQ (tem, Qsw))
4885 error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
4886 dcb.fOutxCtsFlow = FALSE;
4887 dcb.fOutxDsrFlow = FALSE;
4888 dcb.fDtrControl = DTR_CONTROL_DISABLE;
4889 dcb.fDsrSensitivity = FALSE;
4890 dcb.fTXContinueOnXoff = FALSE;
4891 dcb.fOutX = FALSE;
4892 dcb.fInX = FALSE;
4893 dcb.fRtsControl = RTS_CONTROL_DISABLE;
4894 dcb.XonChar = 17; /* Control-Q */
4895 dcb.XoffChar = 19; /* Control-S */
4896 if (NILP (tem))
4898 /* Already configured. */
4900 else if (EQ (tem, Qhw))
4902 dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
4903 dcb.fOutxCtsFlow = TRUE;
4905 else if (EQ (tem, Qsw))
4907 dcb.fOutX = TRUE;
4908 dcb.fInX = TRUE;
4910 childp2 = Fplist_put (childp2, QCflowcontrol, tem);
4912 /* Activate configuration. */
4913 if (!SetCommState (hnd, &dcb))
4914 error ("SetCommState() failed");
4916 childp2 = Fplist_put (childp2, QCsummary, build_string (summary));
4917 p->childp = childp2;
4920 /* end of w32.c */
4922 /* arch-tag: 90442dd3-37be-482b-b272-ac752e3049f1
4923 (do not change this comment) */