1 /* Utility and Unix shadow routines for GNU Emacs on the Microsoft W32 API.
2 Copyright (C) 1994, 1995, 2000, 2001, 2002, 2003, 2004,
3 2005, 2006, 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 */
33 #include <sys/utime.h>
34 #include <mbstring.h> /* for _mbspbrk */
36 /* must include CRT headers *before* config.h */
71 #define _ANONYMOUS_UNION
72 #define _ANONYMOUS_STRUCT
78 #ifdef HAVE_SOCKETS /* TCP connection support, if kernel can do it */
79 #include <sys/socket.h>
103 #include "dispextern.h" /* for xstrcasecmp */
105 /* For serial_configure and serial_open. */
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
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
,
157 PHANDLE TokenHandle
);
158 typedef BOOL (WINAPI
* GetTokenInformation_Proc
) (
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
;
174 const char * const LookupAccountSid_Name
= "LookupAccountSidW";
175 const char * const GetFileSecurity_Name
= "GetFileSecurityW";
177 const char * const LookupAccountSid_Name
= "LookupAccountSidA";
178 const char * const GetFileSecurity_Name
= "GetFileSecurityA";
180 typedef BOOL (WINAPI
* LookupAccountSid_Proc
) (
181 LPCTSTR lpSystemName
,
186 LPDWORD cbDomainName
,
187 PSID_NAME_USE peUse
);
188 typedef PSID_IDENTIFIER_AUTHORITY (WINAPI
* GetSidIdentifierAuthority_Proc
) (
190 typedef PDWORD (WINAPI
* GetSidSubAuthority_Proc
) (
193 typedef PUCHAR (WINAPI
* GetSidSubAuthorityCount_Proc
) (
195 typedef BOOL (WINAPI
* GetFileSecurity_Proc
) (
197 SECURITY_INFORMATION RequestedInformation
,
198 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
200 LPDWORD lpnLengthNeeded
);
201 typedef BOOL (WINAPI
* GetSecurityDescriptorOwner_Proc
) (
202 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
204 LPBOOL lpbOwnerDefaulted
);
205 typedef BOOL (WINAPI
* GetSecurityDescriptorGroup_Proc
) (
206 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
208 LPBOOL lpbGroupDefaulted
);
209 typedef BOOL (WINAPI
* IsValidSid_Proc
) (
212 /* ** A utility function ** */
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
);
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. */
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
;
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
,
278 static OpenProcessToken_Proc s_pfn_Open_Process_Token
= NULL
;
279 HMODULE hm_advapi32
= NULL
;
280 if (is_windows_9x () == TRUE
)
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
)
296 s_pfn_Open_Process_Token (
303 BOOL WINAPI
get_token_information (
305 TOKEN_INFORMATION_CLASS TokenInformationClass
,
306 LPVOID TokenInformation
,
307 DWORD TokenInformationLength
,
310 static GetTokenInformation_Proc s_pfn_Get_Token_Information
= NULL
;
311 HMODULE hm_advapi32
= NULL
;
312 if (is_windows_9x () == TRUE
)
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
)
328 s_pfn_Get_Token_Information (
330 TokenInformationClass
,
332 TokenInformationLength
,
337 BOOL WINAPI
lookup_account_sid (
338 LPCTSTR lpSystemName
,
343 LPDWORD cbDomainName
,
346 static LookupAccountSid_Proc s_pfn_Lookup_Account_Sid
= NULL
;
347 HMODULE hm_advapi32
= NULL
;
348 if (is_windows_9x () == TRUE
)
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
)
364 s_pfn_Lookup_Account_Sid (
375 PSID_IDENTIFIER_AUTHORITY WINAPI
get_sid_identifier_authority (
378 static GetSidIdentifierAuthority_Proc s_pfn_Get_Sid_Identifier_Authority
= NULL
;
379 HMODULE hm_advapi32
= NULL
;
380 if (is_windows_9x () == TRUE
)
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
)
396 return (s_pfn_Get_Sid_Identifier_Authority (pSid
));
399 PDWORD WINAPI
get_sid_sub_authority (
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
)
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
)
422 return (s_pfn_Get_Sid_Sub_Authority (pSid
, n
));
425 PUCHAR WINAPI
get_sid_sub_authority_count (
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
)
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
)
447 return (s_pfn_Get_Sid_Sub_Authority_Count (pSid
));
450 BOOL WINAPI
get_file_security (
452 SECURITY_INFORMATION RequestedInformation
,
453 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
455 LPDWORD lpnLengthNeeded
)
457 static GetFileSecurity_Proc s_pfn_Get_File_Security
= NULL
;
458 HMODULE hm_advapi32
= NULL
;
459 if (is_windows_9x () == TRUE
)
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
)
475 return (s_pfn_Get_File_Security (lpFileName
, RequestedInformation
,
476 pSecurityDescriptor
, nLength
,
480 BOOL WINAPI
get_security_descriptor_owner (
481 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
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
)
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
)
503 return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor
, pOwner
,
507 BOOL WINAPI
get_security_descriptor_group (
508 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
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
)
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
)
530 return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor
, pGroup
,
534 BOOL WINAPI
is_valid_sid (
537 static IsValidSid_Proc s_pfn_Is_Valid_Sid
= NULL
;
538 HMODULE hm_advapi32
= NULL
;
539 if (is_windows_9x () == TRUE
)
543 if (g_b_init_is_valid_sid
== 0)
545 g_b_init_is_valid_sid
= 1;
546 hm_advapi32
= LoadLibrary ("Advapi32.dll");
548 (IsValidSid_Proc
) GetProcAddress (
549 hm_advapi32
, "IsValidSid");
551 if (s_pfn_Is_Valid_Sid
== NULL
)
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. */
567 w32_strerror (int error_no
)
569 static char buf
[500];
572 error_no
= GetLastError ();
575 if (!FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM
, NULL
,
577 0, /* choose most suitable language */
578 buf
, sizeof (buf
), NULL
))
579 sprintf (buf
, "w32 error %u", error_no
);
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
)
591 HANDLE h
= OpenProcess (PROCESS_VM_READ
, FALSE
, GetCurrentProcessId ());
595 unsigned char *buf
= alloca (size
);
596 int retval
= ReadProcessMemory (h
, p
, buf
, size
, &done
);
605 static char startup_dir
[MAXPATHLEN
];
607 /* Get the current working directory. */
612 if (GetCurrentDirectory (MAXPATHLEN
, dir
) > 0)
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
);
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
)
641 /* A faithful emulation is going to have to be saved for a rainy day. */
642 for (i
= 0; i
< nelem
; 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
=
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. */
684 return dflt_passwd
.pw_uid
;
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. */
699 return dflt_passwd
.pw_gid
;
711 if (uid
== dflt_passwd
.pw_uid
)
723 getpwnam (char *name
)
727 pw
= getpwuid (getuid ());
731 if (xstrcasecmp (name
, pw
->pw_name
))
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
);
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 */
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
,
786 strcpy (dflt_group_name
, gname
);
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;
800 dflt_passwd
.pw_uid
= 123;
801 dflt_passwd
.pw_gid
= dflt_passwd
.pw_uid
;
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
)
814 if (getenv ("SHELL") == NULL
)
817 /* Set dir and shell from environment variables. */
818 strcpy (dflt_passwd
.pw_dir
, getenv ("HOME"));
819 strcpy (dflt_passwd
.pw_shell
, getenv ("SHELL"));
828 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
829 return ((rand () << 15) | rand ());
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. */
844 normalize_filename (fp
, path_sep
)
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')
862 if (NILP (Vw32_downcase_file_names
))
866 if (*fp
== '/' || *fp
== '\\')
873 sep
= path_sep
; /* convert to this path separator */
874 elem
= fp
; /* start of current path element */
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 */
900 /* Destructively turn backslashes into slashes. */
902 dostounix_filename (p
)
905 normalize_filename (p
, '/');
908 /* Destructively turn slashes into backslashes. */
910 unixtodos_filename (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.) */
922 register unsigned char *buf
;
924 unsigned char *np
= buf
;
925 unsigned char *startp
= buf
;
926 unsigned char *endp
= buf
+ n
;
930 while (buf
< endp
- 1)
934 if (*(++buf
) != 0x0a)
945 /* Parse the root part of file name, if present. Return length and
946 optionally store pointer to char after root. */
948 parse_root (char * name
, char ** pPath
)
955 /* find the root name of the volume if given */
956 if (isalpha (name
[0]) && name
[1] == ':')
958 /* skip past drive specifier */
960 if (IS_DIRECTORY_SEP (name
[0]))
963 else if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
969 if (IS_DIRECTORY_SEP (*name
) && --slashes
== 0)
974 if (IS_DIRECTORY_SEP (name
[0]))
984 /* Get long base name for name; name is assumed to be absolute. */
986 get_long_basename (char * name
, char * buf
, int size
)
988 WIN32_FIND_DATA find_data
;
992 /* must be valid filename, no wild cards or other invalid characters */
993 if (_mbspbrk (name
, "*?|<>\""))
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);
1003 FindClose (dir_handle
);
1008 /* Get long name for file, if possible (assumed to be absolute). */
1010 w32_get_long_filename (char * name
, char * buf
, int size
)
1015 char full
[ MAX_PATH
];
1018 len
= strlen (name
);
1019 if (len
>= MAX_PATH
)
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
);
1033 while (p
!= NULL
&& *p
)
1036 p
= strchr (q
, '\\');
1038 len
= get_long_basename (full
, o
, size
);
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])
1068 if (_mbspbrk (ptr
+ 2, "*?|<>\"\\/"))
1074 /* Routines that are no-ops on NT but are defined to get Emacs to compile. */
1077 sigsetmask (int signal_mask
)
1095 sigunblock (int sig
)
1101 setpgrp (int pid
, int gid
)
1112 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
1115 w32_get_resource (key
, lpdwtype
)
1120 HKEY hrootkey
= NULL
;
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
)
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
);
1140 RegCloseKey (hrootkey
);
1143 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE
, REG_ROOT
, 0, KEY_READ
, &hrootkey
) == ERROR_SUCCESS
)
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
);
1157 RegCloseKey (hrootkey
);
1163 char *get_emacs_configuration (void);
1164 extern Lisp_Object Vsystem_configuration
;
1167 init_environment (char ** argv
)
1169 static const char * const tempdirs
[] = {
1170 "$TMPDIR", "$TEMP", "$TMP", "c:/"
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
];
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
));
1202 Fcons (build_string ("no usable temporary directories found!!"),
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. */
1212 char locale_name
[32];
1213 struct stat ignored
;
1214 char default_home
[MAX_PATH
];
1216 static const struct env_entry
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
1231 /* {"INFOPATH", "%emacs_dir%/info"}, */
1232 {"EMACSDOC", "%emacs_dir%/etc"},
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
,
1268 /* If we can't get the appdata dir, revert to old behaviour. */
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
;
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. */
1299 char modname
[MAX_PATH
];
1301 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
1303 if ((p
= strrchr (modname
, '\\')) == NULL
)
1307 if ((p
= strrchr (modname
, '\\')) && xstrcasecmp (p
, "\\bin") == 0)
1309 char buf
[SET_ENV_BUF_SIZE
];
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)
1326 p
= strrchr (modname
, '\\');
1330 p
= strrchr (modname
, '\\');
1331 if (p
&& xstrcasecmp (p
, "\\src") == 0)
1333 char buf
[SET_ENV_BUF_SIZE
];
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
))
1352 if ((lpval
= w32_get_resource (env_vars
[i
].name
, &dwType
)) == NULL
1353 /* Also ignore empty environment variables. */
1357 lpval
= env_vars
[i
].def_value
;
1358 dwType
= REG_EXPAND_SZ
;
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
,
1374 _putenv (strdup (buf2
));
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. */
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
))
1415 static char modname
[MAX_PATH
];
1417 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
1419 if ((p
= strrchr (modname
, '\\')) == NULL
)
1423 SetCurrentDirectory (modname
);
1425 /* Ensure argv[0] has the full path to Emacs. */
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
1433 w32_num_mouse_buttons
= GetSystemMetrics (SM_CMOUSEBUTTONS
);
1439 emacs_root_dir (void)
1441 static char root_dir
[FILENAME_MAX
];
1444 p
= getenv ("emacs_dir");
1447 strcpy (root_dir
, p
);
1448 root_dir
[parse_root (root_dir
, NULL
)] = '\0';
1449 dostounix_filename (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
1459 get_emacs_configuration (void)
1461 char *arch
, *oem
, *os
;
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
:
1477 #ifdef PROCESSOR_MIPS_R2000
1478 case PROCESSOR_MIPS_R2000
:
1479 case PROCESSOR_MIPS_R3000
:
1480 case PROCESSOR_MIPS_R4000
:
1485 #ifdef PROCESSOR_ALPHA_21064
1486 case PROCESSOR_ALPHA_21064
:
1496 /* Use the OEM field to reflect the compiler/library combination. */
1498 #define COMPILER_NAME "msvc"
1501 #define COMPILER_NAME "mingw"
1503 #define COMPILER_NAME "unknown"
1506 oem
= COMPILER_NAME
;
1508 switch (osinfo_cache
.dwPlatformId
) {
1509 case VER_PLATFORM_WIN32_NT
:
1511 build_num
= osinfo_cache
.dwBuildNumber
;
1513 case VER_PLATFORM_WIN32_WINDOWS
:
1514 if (osinfo_cache
.dwMinorVersion
== 0) {
1519 build_num
= LOWORD (osinfo_cache
.dwBuildNumber
);
1521 case VER_PLATFORM_WIN32s
:
1522 /* Not supported, should not happen. */
1524 build_num
= LOWORD (osinfo_cache
.dwBuildNumber
);
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
);
1536 sprintf (configuration_buffer
, "%s-%s-%s.%d", arch
, oem
, os
, build_num
);
1539 return configuration_buffer
;
1543 get_emacs_configuration_options (void)
1545 static char options_buffer
[256];
1547 /* Work out the effective configure options for this build. */
1549 #define COMPILER_VERSION "--with-msvc (%d.%02d)", _MSC_VER / 100, _MSC_VER % 100
1552 #define COMPILER_VERSION "--with-gcc (%d.%d)", __GNUC__, __GNUC_MINOR__
1554 #define COMPILER_VERSION ""
1558 sprintf (options_buffer
, COMPILER_VERSION
);
1560 strcat (options_buffer
, " --no-opt");
1563 strcat (options_buffer
, " --cflags");
1564 strcat (options_buffer
, USER_CFLAGS
);
1567 strcat (options_buffer
, " --ldflags");
1568 strcat (options_buffer
, USER_LDFLAGS
);
1570 return options_buffer
;
1574 #include <sys/timeb.h>
1576 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
1578 gettimeofday (struct timeval
*tv
, struct timezone
*tz
)
1583 tv
->tv_sec
= tb
.time
;
1584 tv
->tv_usec
= tb
.millitm
* 1000L;
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). */
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. */
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 */
1628 /* actual volume info */
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)
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). */
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)
1691 parse_root (default_root
, &root_dir
);
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. */
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
))
1722 /* do something */ ;
1726 info
= lookup_volume_info (root_dir
);
1728 if (info
== NULL
|| ! VOLINFO_STILL_VALID (root_dir
, info
))
1736 /* Info is not cached, or is stale. */
1737 if (!GetVolumeInformation (root_dir
,
1738 name
, sizeof (name
),
1742 type
, sizeof (type
)))
1745 /* Cache the volume information for future use, overwriting existing
1746 entry if present. */
1749 info
= (volume_info_data
*) xmalloc (sizeof (volume_info_data
));
1750 add_volume_info (root_dir
, info
);
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 ();
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
;
1781 /* find the root name of the volume if given */
1782 if (isalpha (name
[0]) && name
[1] == ':')
1790 else if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
1797 if (IS_DIRECTORY_SEP (*name
) && --slashes
== 0)
1810 info
= GetCachedVolumeInformation (rootname
);
1813 /* Set global referenced by other functions. */
1814 volume_info
= *info
;
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);
1830 /* Map filename to a valid 8.3 name if necessary. */
1832 map_w32_filename (const char * name
, const char ** pPath
)
1834 static char shortname
[MAX_PATH
];
1835 char * str
= shortname
;
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
, "?");
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 */
1854 *str
++ = *name
++; /* skip past UNC header */
1856 while ((c
= *name
++))
1863 extn
= 0; /* reset extension flags */
1864 dots
= 2; /* max 2 dots */
1865 left
= 8; /* max length 8 for main part */
1869 extn
= 0; /* reset extension flags */
1870 dots
= 2; /* max 2 dots */
1871 left
= 8; /* max length 8 for main part */
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. */
1882 IS_DIRECTORY_SEP (*name
))
1897 extn
= 1; /* we've got an extension */
1898 left
= 3; /* 3 chars in extension */
1902 /* any embedded dots after the first are converted to _ */
1907 case '#': /* don't lose these, they're important */
1909 str
[-1] = c
; /* replace last character of part */
1914 *str
++ = tolower (c
); /* map to lower case (looks nicer) */
1916 dots
= 0; /* started a path component */
1925 strcpy (shortname
, name
);
1926 unixtodos_filename (shortname
);
1930 *pPath
= shortname
+ (path
- save_name
);
1936 is_exec (const char * name
)
1938 char * p
= strrchr (name
, '.');
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
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
);
1965 opendir (char *filename
)
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
)
1974 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
1977 if (is_unc_volume (filename
))
1979 wnet_enum_handle
= open_unc_volume (filename
);
1980 if (wnet_enum_handle
== INVALID_HANDLE_VALUE
)
1984 if (!(dirp
= (DIR *) malloc (sizeof (DIR))))
1991 strncpy (dir_pathname
, map_w32_filename (filename
, NULL
), MAXPATHLEN
);
1992 dir_pathname
[MAXPATHLEN
] = '\0';
1993 dir_is_fat
= is_fat_volume (filename
, NULL
);
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
);
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
,
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];
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
)
2046 if (!FindNextFile (dir_find_handle
, &dir_find_data
))
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. */
2081 strcpy (dir_static
.d_name
, dir_find_data
.cFileName
);
2082 dir_static
.d_namlen
= strlen (dir_static
.d_name
);
2084 _strlwr (dir_static
.d_name
);
2088 for (p
= dir_static
.d_name
; *p
; p
++)
2089 if (*p
>= 'a' && *p
<= 'z')
2092 _strlwr (dir_static
.d_name
);
2099 open_unc_volume (const char *path
)
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
)
2120 return INVALID_HANDLE_VALUE
;
2124 read_unc_volume (HANDLE henum
, char *readbuf
, int size
)
2128 DWORD bufsize
= 512;
2133 buffer
= alloca (bufsize
);
2134 result
= WNetEnumResource (wnet_enum_handle
, &count
, buffer
, &bufsize
);
2135 if (result
!= NO_ERROR
)
2138 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
2139 ptr
= ((LPNETRESOURCE
) buffer
)->lpRemoteName
;
2141 while (*ptr
&& !IS_DIRECTORY_SEP (*ptr
)) ptr
++;
2144 strncpy (readbuf
, ptr
, size
);
2149 close_unc_volume (HANDLE henum
)
2151 if (henum
!= INVALID_HANDLE_VALUE
)
2152 WNetCloseEnum (henum
);
2156 unc_volume_file_attributes (const char *path
)
2161 henum
= open_unc_volume (path
);
2162 if (henum
== INVALID_HANDLE_VALUE
)
2165 attrs
= FILE_ATTRIBUTE_READONLY
| FILE_ATTRIBUTE_DIRECTORY
;
2167 close_unc_volume (henum
);
2172 /* Ensure a network connection is authenticated. */
2174 logon_network_drive (const char *path
)
2176 NETRESOURCE resource
;
2177 char share
[MAX_PATH
];
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
)
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)
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
2214 sys_access (const char * path
, int mode
)
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) {
2228 else if ((attributes
= GetFileAttributes (path
)) == -1)
2230 /* Should try mapping GetLastError to errno; for now just indicate
2231 that path doesn't exist. */
2235 if ((mode
& X_OK
) != 0 && !is_exec (path
))
2240 if ((mode
& W_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_READONLY
) != 0)
2245 if ((mode
& D_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_DIRECTORY
) == 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 */
2274 sys_creat (const char * path
, int mode
)
2276 return _creat (map_w32_filename (path
, NULL
), mode
);
2280 sys_fopen(const char * path
, const char * mode
)
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. */
2292 else if (mode
[0] == 'w' || mode
[0] == 'a')
2293 oflag
= O_WRONLY
| O_CREAT
| O_TRUNC
;
2297 /* Only do simplistic option parsing. */
2301 oflag
&= ~(O_RDONLY
| O_WRONLY
);
2304 else if (mode
[0] == 'b')
2309 else if (mode
[0] == 't')
2316 fd
= _open (map_w32_filename (path
, NULL
), oflag
| _O_NOINHERIT
, 0644);
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)
2329 char oldname
[MAX_PATH
], newname
[MAX_PATH
];
2331 if (old
== NULL
|| new == NULL
)
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
)
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
2354 WIN32_STREAM_ID wid
;
2355 WCHAR wbuffer
[MAX_PATH
]; /* extra space for link name */
2358 wlen
= MultiByteToWideChar (CP_ACP
, MB_PRECOMPOSED
, newname
, -1,
2359 data
.wid
.cStreamName
, MAX_PATH
);
2362 LPVOID context
= NULL
;
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
))
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
);
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
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. */
2412 sys_mktemp (char * template)
2416 unsigned uid
= GetCurrentThreadId ();
2417 static char first_char
[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
2419 if (template == NULL
)
2421 p
= template + strlen (template);
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;
2430 if (i
< 0 && p
[0] == 'X')
2435 int save_errno
= errno
;
2436 p
[0] = first_char
[i
];
2437 if (sys_access (template, 0) < 0)
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 */
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
2459 int res
= _open (mpath
, (oflag
& ~_O_CREAT
) | _O_NOINHERIT
, mode
);
2462 return _open (mpath
, oflag
| _O_NOINHERIT
, mode
);
2466 sys_rename (const char * oldname
, const char * newname
)
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
)
2492 oldname
= map_w32_filename (oldname
, NULL
);
2493 if (o
= strrchr (oldname
, '\\'))
2496 o
= (char *) oldname
;
2498 if (p
= strrchr (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
);
2509 result
= rename (oldname
, temp
);
2511 /* This loop must surely terminate! */
2512 while (result
< 0 && errno
== EEXIST
);
2517 /* Emulate Unix behaviour - 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
);
2533 && _chmod (newname
, 0666) == 0
2534 && _unlink (newname
) == 0)
2535 result
= rename (temp
, newname
);
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;
2561 convert_time (FILETIME ft
)
2567 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
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
;
2584 if (CompareFileTime (&ft
, &utc_base_ft
) < 0)
2587 ret
= (long double) ft
.dwHighDateTime
2588 * 4096.0L * 1024.0L * 1024.0L + ft
.dwLowDateTime
;
2590 return (time_t) (ret
* 1e-7L);
2594 convert_from_time_t (time_t time
, FILETIME
* pft
)
2600 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
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
;
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
);
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). */
2632 hashval (const unsigned char * str
)
2637 h
= (h
<< 4) + *str
++;
2643 /* Return the hash value of the canonical pathname, excluding the
2644 drive/UNC header, to get a hopefully unique inode number. */
2646 generate_inode_val (const char * name
)
2648 char fullname
[ MAX_PATH
];
2652 /* Get the truly canonical filename, if it exists. (Note: this
2653 doesn't resolve aliasing due to subst commands, or recognise hard
2655 if (!w32_get_long_filename ((char *)name
, fullname
, MAX_PATH
))
2658 parse_root (fullname
, &p
);
2659 /* Normal W32 filesystems are still case insensitive. */
2666 static PSECURITY_DESCRIPTOR
2667 get_file_security_desc (const char *fname
)
2669 PSECURITY_DESCRIPTOR psd
= NULL
;
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
)
2681 psd
= xmalloc (sd_len
);
2682 if (!get_file_security (fname
, si
, psd
, sd_len
, &sd_len
))
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);
2708 get_name_and_id (PSECURITY_DESCRIPTOR psd
, const char *fname
,
2709 int *id
, char *nm
, int what
)
2712 char machine
[MAX_COMPUTERNAME_LENGTH
+1];
2714 SID_NAME_USE ignore
;
2716 DWORD name_len
= sizeof (name
);
2718 DWORD domain_len
= sizeof(domain
);
2724 result
= get_security_descriptor_owner (psd
, &sid
, &dflt
);
2725 else if (what
== GID
)
2726 result
= get_security_descriptor_group (psd
, &sid
, &dflt
);
2730 if (!result
|| !is_valid_sid (sid
))
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')
2742 for (s
= fname
+ 2, p
= machine
;
2743 *s
&& !IS_DIRECTORY_SEP (*s
); s
++, p
++)
2749 if (!lookup_account_sid (mp
, sid
, name
, &name_len
,
2750 domain
, &domain_len
, &ignore
)
2751 || name_len
> UNLEN
+1)
2755 *id
= get_rid (sid
);
2763 get_file_owner_and_group (
2764 PSECURITY_DESCRIPTOR psd
,
2768 int dflt_usr
= 0, dflt_grp
= 0;
2777 if (get_name_and_id (psd
, fname
, &st
->st_uid
, st
->st_uname
, UID
))
2779 if (get_name_and_id (psd
, fname
, &st
->st_gid
, st
->st_gname
, GID
))
2782 /* Consider files to belong to current user/group, if we cannot get
2783 more accurate information. */
2786 st
->st_uid
= dflt_passwd
.pw_uid
;
2787 strcpy (st
->st_uname
, dflt_passwd
.pw_name
);
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
)
2803 WIN32_FIND_DATA wfd
;
2805 unsigned __int64 fake_inode
;
2808 int rootdir
= FALSE
;
2809 PSECURITY_DESCRIPTOR psd
= NULL
;
2811 if (path
== NULL
|| buf
== NULL
)
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
2823 if (_mbspbrk (name
, "*?|<>\""))
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')
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
);
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
);
2860 if (!IS_DIRECTORY_SEP (name
[len
-1]))
2861 strcat (name
, "\\");
2862 if (GetDriveType (name
) < 2)
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
);
2876 if (IS_DIRECTORY_SEP (name
[len
-1]))
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]))
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
;
2895 logon_network_drive (name
);
2897 fh
= FindFirstFile (name
, &wfd
);
2898 if (fh
== INVALID_HANDLE_VALUE
)
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
;
2930 fake_inode
+= info
.nFileIndexLow
;
2938 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
2940 buf
->st_mode
= S_IFDIR
;
2944 switch (GetFileType (fh
))
2946 case FILE_TYPE_DISK
:
2947 buf
->st_mode
= S_IFREG
;
2949 case FILE_TYPE_PIPE
:
2950 buf
->st_mode
= S_IFIFO
;
2952 case FILE_TYPE_CHAR
:
2953 case FILE_TYPE_UNKNOWN
:
2955 buf
->st_mode
= S_IFCHR
;
2959 psd
= get_file_security_desc (name
);
2960 get_file_owner_and_group (psd
, name
, buf
);
2964 /* Don't bother to make this information more accurate. */
2965 buf
->st_mode
= (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
2970 get_file_owner_and_group (NULL
, name
, buf
);
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
;
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);
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
;
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);
3024 /* Provide fstat and utime as well as stat for consistent handling of
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
;
3034 switch (GetFileType (fh
) & ~FILE_TYPE_REMOTE
)
3036 case FILE_TYPE_DISK
:
3037 buf
->st_mode
= S_IFREG
;
3038 if (!GetFileInformationByHandle (fh
, &info
))
3044 case FILE_TYPE_PIPE
:
3045 buf
->st_mode
= S_IFIFO
;
3047 case FILE_TYPE_CHAR
:
3048 case FILE_TYPE_UNKNOWN
:
3050 buf
->st_mode
= S_IFCHR
;
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
;
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);
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
;
3104 permission
= S_IREAD
| S_IWRITE
;
3106 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3107 permission
|= S_IEXEC
;
3110 #if 0 /* no way of knowing the filename */
3111 char * p
= strrchr (name
, '.');
3113 (xstrcasecmp (p
, ".exe") == 0 ||
3114 xstrcasecmp (p
, ".com") == 0 ||
3115 xstrcasecmp (p
, ".bat") == 0 ||
3116 xstrcasecmp (p
, ".cmd") == 0))
3117 permission
|= S_IEXEC
;
3121 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
3127 utime (const char *name
, struct utimbuf
*times
)
3129 struct utimbuf deftime
;
3136 deftime
.modtime
= deftime
.actime
= time (NULL
);
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
);
3145 convert_from_time_t (times
->actime
, &atime
);
3146 convert_from_time_t (times
->modtime
, &mtime
);
3147 if (!SetFileTime (fh
, NULL
, &atime
, &mtime
))
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
,
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
3215 static int winsock_inuse
;
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
))
3237 init_winsock (int load_now
)
3239 WSADATA winsockData
;
3241 if (winsock_lib
!= NULL
)
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) \
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
);
3267 LOAD_PROC( connect
);
3268 LOAD_PROC( ioctlsocket
);
3271 LOAD_PROC( closesocket
);
3272 LOAD_PROC( shutdown
);
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
);
3289 /* specify version 1.1 of winsock */
3290 if (pfn_WSAStartup (0x101, &winsockData
) == 0)
3292 if (winsockData
.wVersion
!= 0x101)
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. */
3304 FreeLibrary (winsock_lib
);
3312 FreeLibrary (winsock_lib
);
3322 /* function to set h_errno for compatability; map winsock error codes to
3323 normal system codes where they overlap (non-overlapping definitions
3324 are already in <sys/socket.h> */
3328 if (winsock_lib
== NULL
)
3331 h_errno
= pfn_WSAGetLastError ();
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;
3350 if (h_errno
== 0 && winsock_lib
!= NULL
)
3351 pfn_WSASetLastError (0);
3354 /* Extend strerror to handle the winsock-specific error codes. */
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",
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 */
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",
3431 sys_strerror(int error_no
)
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
);
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))
3456 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
3459 int socket_to_fd (SOCKET s
);
3462 sys_socket(int af
, int type
, int protocol
)
3466 if (winsock_lib
== NULL
)
3469 return INVALID_SOCKET
;
3474 /* call the real socket function */
3475 s
= pfn_socket (af
, type
, protocol
);
3477 if (s
!= INVALID_SOCKET
)
3478 return socket_to_fd (s
);
3484 /* Convert a SOCKET to a file descriptor. */
3486 socket_to_fd (SOCKET s
)
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
);
3501 #ifdef SOCK_REPLACE_HANDLE
3502 /* now replace handle to NUL with our socket handle */
3503 CloseHandle ((HANDLE
) _get_osfhandle (fd
));
3505 _set_osfhnd (fd
, s
);
3506 /* setmode (fd, _O_BINARY); */
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);
3524 HANDLE parent
= GetCurrentProcess ();
3525 HANDLE new_s
= INVALID_HANDLE_VALUE
;
3527 if (DuplicateHandle (parent
,
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
);
3547 CloseHandle (new_s
);
3552 fd_info
[fd
].hnd
= (HANDLE
) s
;
3555 /* set our own internal flags */
3556 fd_info
[fd
].flags
= FILE_SOCKET
| FILE_BINARY
| FILE_READ
| FILE_WRITE
;
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
));
3571 fd_info
[ fd
].cp
= cp
;
3574 winsock_inuse
++; /* count open sockets */
3581 pfn_closesocket (s
);
3588 sys_bind (int s
, const struct sockaddr
* addr
, int namelen
)
3590 if (winsock_lib
== NULL
)
3593 return SOCKET_ERROR
;
3597 if (fd_info
[s
].flags
& FILE_SOCKET
)
3599 int rc
= pfn_bind (SOCK_HANDLE (s
), addr
, namelen
);
3600 if (rc
== SOCKET_ERROR
)
3605 return SOCKET_ERROR
;
3610 sys_connect (int s
, const struct sockaddr
* name
, int namelen
)
3612 if (winsock_lib
== NULL
)
3615 return SOCKET_ERROR
;
3619 if (fd_info
[s
].flags
& FILE_SOCKET
)
3621 int rc
= pfn_connect (SOCK_HANDLE (s
), name
, namelen
);
3622 if (rc
== SOCKET_ERROR
)
3627 return SOCKET_ERROR
;
3631 sys_htons (u_short hostshort
)
3633 return (winsock_lib
!= NULL
) ?
3634 pfn_htons (hostshort
) : hostshort
;
3638 sys_ntohs (u_short netshort
)
3640 return (winsock_lib
!= NULL
) ?
3641 pfn_ntohs (netshort
) : netshort
;
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
);
3661 return SOCKET_ERROR
;
3665 sys_gethostbyname(const char * name
)
3667 struct hostent
* host
;
3669 if (winsock_lib
== NULL
)
3676 host
= pfn_gethostbyname (name
);
3683 sys_getservbyname(const char * name
, const char * proto
)
3685 struct servent
* serv
;
3687 if (winsock_lib
== NULL
)
3694 serv
= pfn_getservbyname (name
, proto
);
3701 sys_getpeername (int s
, struct sockaddr
*addr
, int * namelen
)
3703 if (winsock_lib
== NULL
)
3706 return SOCKET_ERROR
;
3710 if (fd_info
[s
].flags
& FILE_SOCKET
)
3712 int rc
= pfn_getpeername (SOCK_HANDLE (s
), addr
, namelen
);
3713 if (rc
== SOCKET_ERROR
)
3718 return SOCKET_ERROR
;
3723 sys_shutdown (int s
, int how
)
3725 if (winsock_lib
== NULL
)
3728 return SOCKET_ERROR
;
3732 if (fd_info
[s
].flags
& FILE_SOCKET
)
3734 int rc
= pfn_shutdown (SOCK_HANDLE (s
), how
);
3735 if (rc
== SOCKET_ERROR
)
3740 return SOCKET_ERROR
;
3744 sys_setsockopt (int s
, int level
, int optname
, const void * optval
, int optlen
)
3746 if (winsock_lib
== NULL
)
3749 return SOCKET_ERROR
;
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
)
3762 return SOCKET_ERROR
;
3766 sys_listen (int s
, int backlog
)
3768 if (winsock_lib
== NULL
)
3771 return SOCKET_ERROR
;
3775 if (fd_info
[s
].flags
& FILE_SOCKET
)
3777 int rc
= pfn_listen (SOCK_HANDLE (s
), backlog
);
3778 if (rc
== SOCKET_ERROR
)
3781 fd_info
[s
].flags
|= FILE_LISTEN
;
3785 return SOCKET_ERROR
;
3789 sys_getsockname (int s
, struct sockaddr
* name
, int * namelen
)
3791 if (winsock_lib
== NULL
)
3794 return SOCKET_ERROR
;
3798 if (fd_info
[s
].flags
& FILE_SOCKET
)
3800 int rc
= pfn_getsockname (SOCK_HANDLE (s
), name
, namelen
);
3801 if (rc
== SOCKET_ERROR
)
3806 return SOCKET_ERROR
;
3810 sys_accept (int s
, struct sockaddr
* addr
, int * addrlen
)
3812 if (winsock_lib
== NULL
)
3819 if (fd_info
[s
].flags
& FILE_LISTEN
)
3821 SOCKET t
= pfn_accept (SOCK_HANDLE (s
), addr
, addrlen
);
3823 if (t
== INVALID_SOCKET
)
3826 fd
= socket_to_fd (t
);
3828 fd_info
[s
].cp
->status
= STATUS_READ_ACKNOWLEDGED
;
3829 ResetEvent (fd_info
[s
].cp
->char_avail
);
3837 sys_recvfrom (int s
, char * buf
, int len
, int flags
,
3838 struct sockaddr
* from
, int * fromlen
)
3840 if (winsock_lib
== NULL
)
3843 return SOCKET_ERROR
;
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
)
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
)
3865 return SOCKET_ERROR
;
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
)
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
)
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
)
3900 /* Keep track of the fact that we set this to non-blocking. */
3901 fd_info
[s
].flags
|= FILE_NDELAY
;
3907 return SOCKET_ERROR
;
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. */
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 */
3941 for (i
= 0; i
< MAXDESC
; i
++)
3945 if (fd_info
[i
].cp
== cp
)
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
));
3959 winsock_inuse
--; /* count open sockets */
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. */
3973 if (rc
== 0 && fd
< MAXDESC
)
3974 fd_info
[fd
].flags
= 0;
3985 if (new_fd
>= 0 && new_fd
< MAXDESC
)
3987 /* duplicate our internal info as well */
3988 fd_info
[new_fd
] = fd_info
[fd
];
3995 sys_dup2 (int src
, int dst
)
3999 if (dst
< 0 || dst
>= MAXDESC
)
4005 /* make sure we close the destination first if it's a pipe or socket */
4006 if (src
!= dst
&& fd_info
[dst
].flags
!= 0)
4009 rc
= _dup2 (src
, dst
);
4012 /* duplicate our internal info as well */
4013 fd_info
[dst
] = fd_info
[src
];
4018 /* Unix pipe() has only one arg */
4020 sys_pipe (int * phandles
)
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
4029 rc
= _pipe (phandles
, 0, _O_NOINHERIT
| _O_BINARY
);
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]);
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
;
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
)
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
));
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. */
4095 int wait
= w32_pipe_read_delay
;
4101 /* Yield remainder of our time slice, effectively giving a
4102 temporary priority boost to the child process. */
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
;
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
;
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
)
4142 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
4147 if (rc
== sizeof (char))
4148 cp
->status
= STATUS_READ_SUCCEEDED
;
4150 cp
->status
= STATUS_READ_FAILED
;
4156 _sys_wait_accept (int fd
)
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
);
4187 sys_read (int fd
, char * buffer
, unsigned int count
)
4192 char * orig_buffer
= buffer
;
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)
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 ();
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. */
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 */
4237 fd_info
[fd
].flags
|= FILE_AT_EOF
;
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
;
4246 case STATUS_READ_SUCCEEDED
:
4247 /* consume read-ahead char */
4248 *buffer
++ = cp
->chr
;
4251 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
4252 ResetEvent (cp
->char_avail
);
4254 case STATUS_READ_ACKNOWLEDGED
:
4258 DebPrint (("sys_read: bad status %d\n", current_status
));
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
);
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
;
4281 /* Configure timeouts for non-blocking read. */
4282 if (!GetCommTimeouts (hnd
, &ct
))
4287 ct
.ReadIntervalTimeout
= MAXDWORD
;
4288 ct
.ReadTotalTimeoutMultiplier
= 0;
4289 ct
.ReadTotalTimeoutConstant
= 0;
4290 if (!SetCommTimeouts (hnd
, &ct
))
4296 if (!ResetEvent (ovl
->hEvent
))
4301 if (!ReadFile (hnd
, buffer
, count
, (DWORD
*) &rc
, ovl
))
4303 if (GetLastError () != ERROR_IO_PENDING
)
4308 if (!GetOverlappedResult (hnd
, ovl
, (DWORD
*) &rc
, TRUE
))
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
;
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
)));
4348 int nread
= _read (fd
, buffer
, count
);
4351 else 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
;
4373 nchars
= _read (fd
, buffer
, count
);
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
)
4393 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
| FILE_SERIAL
))
4395 if ((fd_info
[fd
].flags
& FILE_WRITE
) == 0)
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
;
4411 unsigned char *next
;
4412 /* copy next line or remaining bytes */
4413 next
= _memccpy (dst
, src
, '\n', nbytes
);
4416 /* copied one line ending with '\n' */
4417 int copied
= next
- dst
;
4420 /* insert '\r' before '\n' */
4427 /* copied remaining partial line -> now finished */
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
};
4441 if (!WriteFile (hnd
, buffer
, count
, (DWORD
*) &nchars
, ovl
))
4443 if (GetLastError () != ERROR_IO_PENDING
)
4448 if (detect_input_pending ())
4449 active
= MsgWaitForMultipleObjects (2, wait_hnd
, FALSE
, INFINITE
,
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
);
4461 if (active
== WAIT_OBJECT_0
+ 1
4462 && !GetOverlappedResult (hnd
, ovl
, (DWORD
*) &nchars
, TRUE
))
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
)
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
)));
4500 nchars
= _write (fd
, buffer
, count
);
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
;
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
);
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
));
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"
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
);
4548 "Emacs Abort Dialog",
4549 MB_OK
| MB_ICONEXCLAMATION
| MB_TASKMODAL
);
4550 /* Use the low-level Emacs abort. */
4565 /* shutdown the socket interface if necessary */
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. */
4587 if (getenv ("PRELOAD_WINSOCK") != NULL
)
4588 init_winsock (TRUE
);
4591 /* Initial preparation for subprocess support: replace our standard
4592 handles with non-inheritable versions. */
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
),
4609 DUPLICATE_SAME_ACCESS
);
4611 DuplicateHandle (parent
,
4612 GetStdHandle (STD_OUTPUT_HANDLE
),
4617 DUPLICATE_SAME_ACCESS
);
4619 DuplicateHandle (parent
,
4620 GetStdHandle (STD_ERROR_HANDLE
),
4625 DUPLICATE_SAME_ACCESS
);
4631 if (stdin_save
!= INVALID_HANDLE_VALUE
)
4632 _open_osfhandle ((long) stdin_save
, O_TEXT
);
4634 _open ("nul", O_TEXT
| O_NOINHERIT
| O_RDONLY
);
4637 if (stdout_save
!= INVALID_HANDLE_VALUE
)
4638 _open_osfhandle ((long) stdout_save
, O_TEXT
);
4640 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
4643 if (stderr_save
!= INVALID_HANDLE_VALUE
)
4644 _open_osfhandle ((long) stderr_save
, O_TEXT
);
4646 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
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
);
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. */
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).
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
)
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);
4743 error ("Could not open %s", port
);
4747 error ("Could not create child process");
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");
4768 /* For serial-process-configure */
4770 serial_configure (struct Lisp_Process
*p
,
4771 Lisp_Object contact
)
4773 Lisp_Object childp2
= Qnil
;
4774 Lisp_Object tem
= Qnil
;
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");
4803 dcb
.fAbortOnError
= FALSE
;
4804 /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
4809 /* Configure speed. */
4810 if (!NILP (Fplist_member (contact
, QCspeed
)))
4811 tem
= Fplist_get (contact
, QCspeed
);
4813 tem
= Fplist_get (p
->childp
, QCspeed
);
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
);
4822 tem
= Fplist_get (p
->childp
, QCbytesize
);
4824 tem
= make_number (8);
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
);
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
;
4846 else if (EQ (tem
, Qeven
))
4850 dcb
.Parity
= EVENPARITY
;
4851 dcb
.fErrorChar
= TRUE
;
4853 else if (EQ (tem
, Qodd
))
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
);
4866 tem
= Fplist_get (p
->childp
, QCstopbits
);
4868 tem
= make_number (1);
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
);
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
;
4893 dcb
.fRtsControl
= RTS_CONTROL_DISABLE
;
4894 dcb
.XonChar
= 17; /* Control-Q */
4895 dcb
.XoffChar
= 19; /* Control-S */
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
))
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
;
4922 /* arch-tag: 90442dd3-37be-482b-b272-ac752e3049f1
4923 (do not change this comment) */