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, or (at your option)
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; see the file COPYING. If not, write to
19 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 Boston, MA 02110-1301, USA.
22 Geoff Voelker (voelker@cs.washington.edu) 7-29-94
24 #include <stddef.h> /* for offsetof */
34 #include <sys/utime.h>
35 #include <mbstring.h> /* for _mbspbrk */
37 /* must include CRT headers *before* config.h */
72 #define _ANONYMOUS_UNION
73 #define _ANONYMOUS_STRUCT
79 #ifdef HAVE_SOCKETS /* TCP connection support, if kernel can do it */
80 #include <sys/socket.h>
105 typedef HRESULT (WINAPI
* ShGetFolderPath_fn
)
106 (IN HWND
, IN
int, IN HANDLE
, IN DWORD
, OUT
char *);
108 void globals_of_w32 ();
109 static DWORD
get_rid (PSID
);
111 extern Lisp_Object Vw32_downcase_file_names
;
112 extern Lisp_Object Vw32_generate_fake_inodes
;
113 extern Lisp_Object Vw32_get_true_file_attributes
;
114 /* Defined in process.c for its own purpose. */
115 extern Lisp_Object Qlocal
;
117 extern int w32_num_mouse_buttons
;
120 /* Initialization states.
122 WARNING: If you add any more such variables for additional APIs,
123 you MUST add initialization for them to globals_of_w32
124 below. This is because these variables might get set
125 to non-NULL values during dumping, but the dumped Emacs
126 cannot reuse those values, because it could be run on a
127 different version of the OS, where API addresses are
129 static BOOL g_b_init_is_windows_9x
;
130 static BOOL g_b_init_open_process_token
;
131 static BOOL g_b_init_get_token_information
;
132 static BOOL g_b_init_lookup_account_sid
;
133 static BOOL g_b_init_get_sid_identifier_authority
;
134 static BOOL g_b_init_get_sid_sub_authority
;
135 static BOOL g_b_init_get_sid_sub_authority_count
;
136 static BOOL g_b_init_get_file_security
;
137 static BOOL g_b_init_get_security_descriptor_owner
;
138 static BOOL g_b_init_get_security_descriptor_group
;
139 static BOOL g_b_init_is_valid_sid
;
142 BEGIN: Wrapper functions around OpenProcessToken
143 and other functions in advapi32.dll that are only
144 supported in Windows NT / 2k / XP
146 /* ** Function pointer typedefs ** */
147 typedef BOOL (WINAPI
* OpenProcessToken_Proc
) (
148 HANDLE ProcessHandle
,
150 PHANDLE TokenHandle
);
151 typedef BOOL (WINAPI
* GetTokenInformation_Proc
) (
153 TOKEN_INFORMATION_CLASS TokenInformationClass
,
154 LPVOID TokenInformation
,
155 DWORD TokenInformationLength
,
156 PDWORD ReturnLength
);
157 typedef BOOL (WINAPI
* GetProcessTimes_Proc
) (
158 HANDLE process_handle
,
159 LPFILETIME creation_time
,
160 LPFILETIME exit_time
,
161 LPFILETIME kernel_time
,
162 LPFILETIME user_time
);
164 GetProcessTimes_Proc get_process_times_fn
= NULL
;
167 const char * const LookupAccountSid_Name
= "LookupAccountSidW";
168 const char * const GetFileSecurity_Name
= "GetFileSecurityW";
170 const char * const LookupAccountSid_Name
= "LookupAccountSidA";
171 const char * const GetFileSecurity_Name
= "GetFileSecurityA";
173 typedef BOOL (WINAPI
* LookupAccountSid_Proc
) (
174 LPCTSTR lpSystemName
,
179 LPDWORD cbDomainName
,
180 PSID_NAME_USE peUse
);
181 typedef PSID_IDENTIFIER_AUTHORITY (WINAPI
* GetSidIdentifierAuthority_Proc
) (
183 typedef PDWORD (WINAPI
* GetSidSubAuthority_Proc
) (
186 typedef PUCHAR (WINAPI
* GetSidSubAuthorityCount_Proc
) (
188 typedef BOOL (WINAPI
* GetFileSecurity_Proc
) (
190 SECURITY_INFORMATION RequestedInformation
,
191 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
193 LPDWORD lpnLengthNeeded
);
194 typedef BOOL (WINAPI
* GetSecurityDescriptorOwner_Proc
) (
195 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
197 LPBOOL lpbOwnerDefaulted
);
198 typedef BOOL (WINAPI
* GetSecurityDescriptorGroup_Proc
) (
199 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
201 LPBOOL lpbGroupDefaulted
);
202 typedef BOOL (WINAPI
* IsValidSid_Proc
) (
205 /* ** A utility function ** */
209 static BOOL s_b_ret
=0;
210 OSVERSIONINFO os_ver
;
211 if (g_b_init_is_windows_9x
== 0)
213 g_b_init_is_windows_9x
= 1;
214 ZeroMemory(&os_ver
, sizeof(OSVERSIONINFO
));
215 os_ver
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFO
);
216 if (GetVersionEx (&os_ver
))
218 s_b_ret
= (os_ver
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
);
224 /* Get total user and system times for get-internal-run-time.
225 Returns a list of three integers if the times are provided by the OS
226 (NT derivatives), otherwise it returns the result of current-time. */
228 w32_get_internal_run_time ()
230 if (get_process_times_fn
)
232 FILETIME create
, exit
, kernel
, user
;
233 HANDLE proc
= GetCurrentProcess();
234 if ((*get_process_times_fn
) (proc
, &create
, &exit
, &kernel
, &user
))
236 LARGE_INTEGER user_int
, kernel_int
, total
;
238 user_int
.LowPart
= user
.dwLowDateTime
;
239 user_int
.HighPart
= user
.dwHighDateTime
;
240 kernel_int
.LowPart
= kernel
.dwLowDateTime
;
241 kernel_int
.HighPart
= kernel
.dwHighDateTime
;
242 total
.QuadPart
= user_int
.QuadPart
+ kernel_int
.QuadPart
;
243 /* FILETIME is 100 nanosecond increments, Emacs only wants
244 microsecond resolution. */
245 total
.QuadPart
/= 10;
246 microseconds
= total
.QuadPart
% 1000000;
247 total
.QuadPart
/= 1000000;
249 /* Sanity check to make sure we can represent the result. */
250 if (total
.HighPart
== 0)
252 int secs
= total
.LowPart
;
254 return list3 (make_number ((secs
>> 16) & 0xffff),
255 make_number (secs
& 0xffff),
256 make_number (microseconds
));
261 return Fcurrent_time ();
264 /* ** The wrapper functions ** */
266 BOOL WINAPI
open_process_token (
267 HANDLE ProcessHandle
,
271 static OpenProcessToken_Proc s_pfn_Open_Process_Token
= NULL
;
272 HMODULE hm_advapi32
= NULL
;
273 if (is_windows_9x () == TRUE
)
277 if (g_b_init_open_process_token
== 0)
279 g_b_init_open_process_token
= 1;
280 hm_advapi32
= LoadLibrary ("Advapi32.dll");
281 s_pfn_Open_Process_Token
=
282 (OpenProcessToken_Proc
) GetProcAddress (hm_advapi32
, "OpenProcessToken");
284 if (s_pfn_Open_Process_Token
== NULL
)
289 s_pfn_Open_Process_Token (
296 BOOL WINAPI
get_token_information (
298 TOKEN_INFORMATION_CLASS TokenInformationClass
,
299 LPVOID TokenInformation
,
300 DWORD TokenInformationLength
,
303 static GetTokenInformation_Proc s_pfn_Get_Token_Information
= NULL
;
304 HMODULE hm_advapi32
= NULL
;
305 if (is_windows_9x () == TRUE
)
309 if (g_b_init_get_token_information
== 0)
311 g_b_init_get_token_information
= 1;
312 hm_advapi32
= LoadLibrary ("Advapi32.dll");
313 s_pfn_Get_Token_Information
=
314 (GetTokenInformation_Proc
) GetProcAddress (hm_advapi32
, "GetTokenInformation");
316 if (s_pfn_Get_Token_Information
== NULL
)
321 s_pfn_Get_Token_Information (
323 TokenInformationClass
,
325 TokenInformationLength
,
330 BOOL WINAPI
lookup_account_sid (
331 LPCTSTR lpSystemName
,
336 LPDWORD cbDomainName
,
339 static LookupAccountSid_Proc s_pfn_Lookup_Account_Sid
= NULL
;
340 HMODULE hm_advapi32
= NULL
;
341 if (is_windows_9x () == TRUE
)
345 if (g_b_init_lookup_account_sid
== 0)
347 g_b_init_lookup_account_sid
= 1;
348 hm_advapi32
= LoadLibrary ("Advapi32.dll");
349 s_pfn_Lookup_Account_Sid
=
350 (LookupAccountSid_Proc
) GetProcAddress (hm_advapi32
, LookupAccountSid_Name
);
352 if (s_pfn_Lookup_Account_Sid
== NULL
)
357 s_pfn_Lookup_Account_Sid (
368 PSID_IDENTIFIER_AUTHORITY WINAPI
get_sid_identifier_authority (
371 static GetSidIdentifierAuthority_Proc s_pfn_Get_Sid_Identifier_Authority
= NULL
;
372 HMODULE hm_advapi32
= NULL
;
373 if (is_windows_9x () == TRUE
)
377 if (g_b_init_get_sid_identifier_authority
== 0)
379 g_b_init_get_sid_identifier_authority
= 1;
380 hm_advapi32
= LoadLibrary ("Advapi32.dll");
381 s_pfn_Get_Sid_Identifier_Authority
=
382 (GetSidIdentifierAuthority_Proc
) GetProcAddress (
383 hm_advapi32
, "GetSidIdentifierAuthority");
385 if (s_pfn_Get_Sid_Identifier_Authority
== NULL
)
389 return (s_pfn_Get_Sid_Identifier_Authority (pSid
));
392 PDWORD WINAPI
get_sid_sub_authority (
396 static GetSidSubAuthority_Proc s_pfn_Get_Sid_Sub_Authority
= NULL
;
397 static DWORD zero
= 0U;
398 HMODULE hm_advapi32
= NULL
;
399 if (is_windows_9x () == TRUE
)
403 if (g_b_init_get_sid_sub_authority
== 0)
405 g_b_init_get_sid_sub_authority
= 1;
406 hm_advapi32
= LoadLibrary ("Advapi32.dll");
407 s_pfn_Get_Sid_Sub_Authority
=
408 (GetSidSubAuthority_Proc
) GetProcAddress (
409 hm_advapi32
, "GetSidSubAuthority");
411 if (s_pfn_Get_Sid_Sub_Authority
== NULL
)
415 return (s_pfn_Get_Sid_Sub_Authority (pSid
, n
));
418 PUCHAR WINAPI
get_sid_sub_authority_count (
421 static GetSidSubAuthorityCount_Proc s_pfn_Get_Sid_Sub_Authority_Count
= NULL
;
422 static UCHAR zero
= 0U;
423 HMODULE hm_advapi32
= NULL
;
424 if (is_windows_9x () == TRUE
)
428 if (g_b_init_get_sid_sub_authority_count
== 0)
430 g_b_init_get_sid_sub_authority_count
= 1;
431 hm_advapi32
= LoadLibrary ("Advapi32.dll");
432 s_pfn_Get_Sid_Sub_Authority_Count
=
433 (GetSidSubAuthorityCount_Proc
) GetProcAddress (
434 hm_advapi32
, "GetSidSubAuthorityCount");
436 if (s_pfn_Get_Sid_Sub_Authority_Count
== NULL
)
440 return (s_pfn_Get_Sid_Sub_Authority_Count (pSid
));
443 BOOL WINAPI
get_file_security (
445 SECURITY_INFORMATION RequestedInformation
,
446 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
448 LPDWORD lpnLengthNeeded
)
450 static GetFileSecurity_Proc s_pfn_Get_File_Security
= NULL
;
451 HMODULE hm_advapi32
= NULL
;
452 if (is_windows_9x () == TRUE
)
456 if (g_b_init_get_file_security
== 0)
458 g_b_init_get_file_security
= 1;
459 hm_advapi32
= LoadLibrary ("Advapi32.dll");
460 s_pfn_Get_File_Security
=
461 (GetFileSecurity_Proc
) GetProcAddress (
462 hm_advapi32
, GetFileSecurity_Name
);
464 if (s_pfn_Get_File_Security
== NULL
)
468 return (s_pfn_Get_File_Security (lpFileName
, RequestedInformation
,
469 pSecurityDescriptor
, nLength
,
473 BOOL WINAPI
get_security_descriptor_owner (
474 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
476 LPBOOL lpbOwnerDefaulted
)
478 static GetSecurityDescriptorOwner_Proc s_pfn_Get_Security_Descriptor_Owner
= NULL
;
479 HMODULE hm_advapi32
= NULL
;
480 if (is_windows_9x () == TRUE
)
484 if (g_b_init_get_security_descriptor_owner
== 0)
486 g_b_init_get_security_descriptor_owner
= 1;
487 hm_advapi32
= LoadLibrary ("Advapi32.dll");
488 s_pfn_Get_Security_Descriptor_Owner
=
489 (GetSecurityDescriptorOwner_Proc
) GetProcAddress (
490 hm_advapi32
, "GetSecurityDescriptorOwner");
492 if (s_pfn_Get_Security_Descriptor_Owner
== NULL
)
496 return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor
, pOwner
,
500 BOOL WINAPI
get_security_descriptor_group (
501 PSECURITY_DESCRIPTOR pSecurityDescriptor
,
503 LPBOOL lpbGroupDefaulted
)
505 static GetSecurityDescriptorGroup_Proc s_pfn_Get_Security_Descriptor_Group
= NULL
;
506 HMODULE hm_advapi32
= NULL
;
507 if (is_windows_9x () == TRUE
)
511 if (g_b_init_get_security_descriptor_group
== 0)
513 g_b_init_get_security_descriptor_group
= 1;
514 hm_advapi32
= LoadLibrary ("Advapi32.dll");
515 s_pfn_Get_Security_Descriptor_Group
=
516 (GetSecurityDescriptorGroup_Proc
) GetProcAddress (
517 hm_advapi32
, "GetSecurityDescriptorGroup");
519 if (s_pfn_Get_Security_Descriptor_Group
== NULL
)
523 return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor
, pGroup
,
527 BOOL WINAPI
is_valid_sid (
530 static IsValidSid_Proc s_pfn_Is_Valid_Sid
= NULL
;
531 HMODULE hm_advapi32
= NULL
;
532 if (is_windows_9x () == TRUE
)
536 if (g_b_init_is_valid_sid
== 0)
538 g_b_init_is_valid_sid
= 1;
539 hm_advapi32
= LoadLibrary ("Advapi32.dll");
541 (IsValidSid_Proc
) GetProcAddress (
542 hm_advapi32
, "IsValidSid");
544 if (s_pfn_Is_Valid_Sid
== NULL
)
548 return (s_pfn_Is_Valid_Sid (sid
));
552 END: Wrapper functions around OpenProcessToken
553 and other functions in advapi32.dll that are only
554 supported in Windows NT / 2k / XP
558 /* Equivalent of strerror for W32 error codes. */
560 w32_strerror (int error_no
)
562 static char buf
[500];
565 error_no
= GetLastError ();
568 if (!FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM
, NULL
,
570 0, /* choose most suitable language */
571 buf
, sizeof (buf
), NULL
))
572 sprintf (buf
, "w32 error %u", error_no
);
576 /* Return 1 if P is a valid pointer to an object of size SIZE. Return
577 0 if P is NOT a valid pointer. Return -1 if we cannot validate P.
579 This is called from alloc.c:valid_pointer_p. */
581 w32_valid_pointer_p (void *p
, int size
)
584 HANDLE h
= OpenProcess (PROCESS_VM_READ
, FALSE
, GetCurrentProcessId ());
588 unsigned char *buf
= alloca (size
);
589 int retval
= ReadProcessMemory (h
, p
, buf
, size
, &done
);
598 static char startup_dir
[MAXPATHLEN
];
600 /* Get the current working directory. */
605 if (GetCurrentDirectory (MAXPATHLEN
, dir
) > 0)
609 /* Emacs doesn't actually change directory itself, and we want to
610 force our real wd to be where emacs.exe is to avoid unnecessary
611 conflicts when trying to rename or delete directories. */
612 strcpy (dir
, startup_dir
);
618 /* Emulate gethostname. */
620 gethostname (char *buffer
, int size
)
622 /* NT only allows small host names, so the buffer is
623 certainly large enough. */
624 return !GetComputerName (buffer
, &size
);
626 #endif /* HAVE_SOCKETS */
628 /* Emulate getloadavg. */
630 getloadavg (double loadavg
[], int nelem
)
634 /* A faithful emulation is going to have to be saved for a rainy day. */
635 for (i
= 0; i
< nelem
; i
++)
642 /* Emulate getpwuid, getpwnam and others. */
644 #define PASSWD_FIELD_SIZE 256
646 static char dflt_passwd_name
[PASSWD_FIELD_SIZE
];
647 static char dflt_passwd_passwd
[PASSWD_FIELD_SIZE
];
648 static char dflt_passwd_gecos
[PASSWD_FIELD_SIZE
];
649 static char dflt_passwd_dir
[PASSWD_FIELD_SIZE
];
650 static char dflt_passwd_shell
[PASSWD_FIELD_SIZE
];
652 static struct passwd dflt_passwd
=
664 static char dflt_group_name
[GNLEN
+1];
666 static struct group dflt_group
=
668 /* When group information is not available, we return this as the
669 group for all files. */
677 return dflt_passwd
.pw_uid
;
683 /* I could imagine arguing for checking to see whether the user is
684 in the Administrators group and returning a UID of 0 for that
685 case, but I don't know how wise that would be in the long run. */
692 return dflt_passwd
.pw_gid
;
704 if (uid
== dflt_passwd
.pw_uid
)
716 getpwnam (char *name
)
720 pw
= getpwuid (getuid ());
724 if (stricmp (name
, pw
->pw_name
))
733 /* Find the user's real name by opening the process token and
734 looking up the name associated with the user-sid in that token.
736 Use the relative portion of the identifier authority value from
737 the user-sid as the user id value (same for group id using the
738 primary group sid from the process token). */
740 char uname
[UNLEN
+1], gname
[GNLEN
+1], domain
[1025];
741 DWORD ulength
= sizeof (uname
), dlength
= sizeof (domain
), trash
;
742 DWORD glength
= sizeof (gname
);
744 SID_NAME_USE user_type
;
745 unsigned char buf
[1024];
746 TOKEN_USER user_token
;
747 TOKEN_PRIMARY_GROUP group_token
;
749 if (open_process_token (GetCurrentProcess (), TOKEN_QUERY
, &token
)
750 && get_token_information (token
, TokenUser
,
751 (PVOID
)buf
, sizeof (buf
), &trash
)
752 && (memcpy (&user_token
, buf
, sizeof (user_token
)),
753 lookup_account_sid (NULL
, user_token
.User
.Sid
, uname
, &ulength
,
754 domain
, &dlength
, &user_type
)))
756 strcpy (dflt_passwd
.pw_name
, uname
);
757 /* Determine a reasonable uid value. */
758 if (stricmp ("administrator", uname
) == 0)
760 dflt_passwd
.pw_uid
= 500; /* well-known Administrator uid */
761 dflt_passwd
.pw_gid
= 513; /* well-known None gid */
765 /* Use the last sub-authority value of the RID, the relative
766 portion of the SID, as user/group ID. */
767 dflt_passwd
.pw_uid
= get_rid (user_token
.User
.Sid
);
769 /* Get group id and name. */
770 if (get_token_information (token
, TokenPrimaryGroup
,
771 (PVOID
)buf
, sizeof (buf
), &trash
))
773 memcpy (&group_token
, buf
, sizeof (group_token
));
774 dflt_passwd
.pw_gid
= get_rid (group_token
.PrimaryGroup
);
775 dlength
= sizeof (domain
);
776 if (lookup_account_sid (NULL
, group_token
.PrimaryGroup
,
777 gname
, &glength
, NULL
, &dlength
,
779 strcpy (dflt_group_name
, gname
);
782 dflt_passwd
.pw_gid
= dflt_passwd
.pw_uid
;
785 /* If security calls are not supported (presumably because we
786 are running under Windows 95), fallback to this. */
787 else if (GetUserName (uname
, &ulength
))
789 strcpy (dflt_passwd
.pw_name
, uname
);
790 if (stricmp ("administrator", uname
) == 0)
791 dflt_passwd
.pw_uid
= 0;
793 dflt_passwd
.pw_uid
= 123;
794 dflt_passwd
.pw_gid
= dflt_passwd
.pw_uid
;
798 strcpy (dflt_passwd
.pw_name
, "unknown");
799 dflt_passwd
.pw_uid
= 123;
800 dflt_passwd
.pw_gid
= 123;
802 dflt_group
.gr_gid
= dflt_passwd
.pw_gid
;
804 /* Ensure HOME and SHELL are defined. */
805 if (getenv ("HOME") == NULL
)
807 if (getenv ("SHELL") == NULL
)
810 /* Set dir and shell from environment variables. */
811 strcpy (dflt_passwd
.pw_dir
, getenv ("HOME"));
812 strcpy (dflt_passwd
.pw_shell
, getenv ("SHELL"));
821 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
822 return ((rand () << 15) | rand ());
832 /* Normalize filename by converting all path separators to
833 the specified separator. Also conditionally convert upper
834 case path name components to lower case. */
837 normalize_filename (fp
, path_sep
)
844 /* Always lower-case drive letters a-z, even if the filesystem
845 preserves case in filenames.
846 This is so filenames can be compared by string comparison
847 functions that are case-sensitive. Even case-preserving filesystems
848 do not distinguish case in drive letters. */
849 if (fp
[1] == ':' && *fp
>= 'A' && *fp
<= 'Z')
855 if (NILP (Vw32_downcase_file_names
))
859 if (*fp
== '/' || *fp
== '\\')
866 sep
= path_sep
; /* convert to this path separator */
867 elem
= fp
; /* start of current path element */
870 if (*fp
>= 'a' && *fp
<= 'z')
871 elem
= 0; /* don't convert this element */
873 if (*fp
== 0 || *fp
== ':')
875 sep
= *fp
; /* restore current separator (or 0) */
876 *fp
= '/'; /* after conversion of this element */
879 if (*fp
== '/' || *fp
== '\\')
881 if (elem
&& elem
!= fp
)
883 *fp
= 0; /* temporary end of string */
884 _strlwr (elem
); /* while we convert to lower case */
886 *fp
= sep
; /* convert (or restore) path separator */
887 elem
= fp
+ 1; /* next element starts after separator */
893 /* Destructively turn backslashes into slashes. */
895 dostounix_filename (p
)
898 normalize_filename (p
, '/');
901 /* Destructively turn slashes into backslashes. */
903 unixtodos_filename (p
)
906 normalize_filename (p
, '\\');
909 /* Remove all CR's that are followed by a LF.
910 (From msdos.c...probably should figure out a way to share it,
911 although this code isn't going to ever change.) */
915 register unsigned char *buf
;
917 unsigned char *np
= buf
;
918 unsigned char *startp
= buf
;
919 unsigned char *endp
= buf
+ n
;
923 while (buf
< endp
- 1)
927 if (*(++buf
) != 0x0a)
938 /* Parse the root part of file name, if present. Return length and
939 optionally store pointer to char after root. */
941 parse_root (char * name
, char ** pPath
)
948 /* find the root name of the volume if given */
949 if (isalpha (name
[0]) && name
[1] == ':')
951 /* skip past drive specifier */
953 if (IS_DIRECTORY_SEP (name
[0]))
956 else if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
962 if (IS_DIRECTORY_SEP (*name
) && --slashes
== 0)
967 if (IS_DIRECTORY_SEP (name
[0]))
977 /* Get long base name for name; name is assumed to be absolute. */
979 get_long_basename (char * name
, char * buf
, int size
)
981 WIN32_FIND_DATA find_data
;
985 /* must be valid filename, no wild cards or other invalid characters */
986 if (_mbspbrk (name
, "*?|<>\""))
989 dir_handle
= FindFirstFile (name
, &find_data
);
990 if (dir_handle
!= INVALID_HANDLE_VALUE
)
992 if ((len
= strlen (find_data
.cFileName
)) < size
)
993 memcpy (buf
, find_data
.cFileName
, len
+ 1);
996 FindClose (dir_handle
);
1001 /* Get long name for file, if possible (assumed to be absolute). */
1003 w32_get_long_filename (char * name
, char * buf
, int size
)
1008 char full
[ MAX_PATH
];
1011 len
= strlen (name
);
1012 if (len
>= MAX_PATH
)
1015 /* Use local copy for destructive modification. */
1016 memcpy (full
, name
, len
+1);
1017 unixtodos_filename (full
);
1019 /* Copy root part verbatim. */
1020 len
= parse_root (full
, &p
);
1021 memcpy (o
, full
, len
);
1026 while (p
!= NULL
&& *p
)
1029 p
= strchr (q
, '\\');
1031 len
= get_long_basename (full
, o
, size
);
1054 is_unc_volume (const char *filename
)
1056 const char *ptr
= filename
;
1058 if (!IS_DIRECTORY_SEP (ptr
[0]) || !IS_DIRECTORY_SEP (ptr
[1]) || !ptr
[2])
1061 if (_mbspbrk (ptr
+ 2, "*?|<>\"\\/"))
1067 /* Routines that are no-ops on NT but are defined to get Emacs to compile. */
1070 sigsetmask (int signal_mask
)
1088 sigunblock (int sig
)
1094 setpgrp (int pid
, int gid
)
1105 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
1108 w32_get_resource (key
, lpdwtype
)
1113 HKEY hrootkey
= NULL
;
1116 /* Check both the current user and the local machine to see if
1117 we have any resources. */
1119 if (RegOpenKeyEx (HKEY_CURRENT_USER
, REG_ROOT
, 0, KEY_READ
, &hrootkey
) == ERROR_SUCCESS
)
1123 if (RegQueryValueEx (hrootkey
, key
, NULL
, NULL
, NULL
, &cbData
) == ERROR_SUCCESS
1124 && (lpvalue
= (LPBYTE
) xmalloc (cbData
)) != NULL
1125 && RegQueryValueEx (hrootkey
, key
, NULL
, lpdwtype
, lpvalue
, &cbData
) == ERROR_SUCCESS
)
1127 RegCloseKey (hrootkey
);
1131 if (lpvalue
) xfree (lpvalue
);
1133 RegCloseKey (hrootkey
);
1136 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE
, REG_ROOT
, 0, KEY_READ
, &hrootkey
) == ERROR_SUCCESS
)
1140 if (RegQueryValueEx (hrootkey
, key
, NULL
, NULL
, NULL
, &cbData
) == ERROR_SUCCESS
1141 && (lpvalue
= (LPBYTE
) xmalloc (cbData
)) != NULL
1142 && RegQueryValueEx (hrootkey
, key
, NULL
, lpdwtype
, lpvalue
, &cbData
) == ERROR_SUCCESS
)
1144 RegCloseKey (hrootkey
);
1148 if (lpvalue
) xfree (lpvalue
);
1150 RegCloseKey (hrootkey
);
1156 char *get_emacs_configuration (void);
1157 extern Lisp_Object Vsystem_configuration
;
1160 init_environment (char ** argv
)
1162 static const char * const tempdirs
[] = {
1163 "$TMPDIR", "$TEMP", "$TMP", "c:/"
1168 const int imax
= sizeof (tempdirs
) / sizeof (tempdirs
[0]);
1170 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
1171 temporary files and assume "/tmp" if $TMPDIR is unset, which
1172 will break on DOS/Windows. Refuse to work if we cannot find
1173 a directory, not even "c:/", usable for that purpose. */
1174 for (i
= 0; i
< imax
; i
++)
1176 const char *tmp
= tempdirs
[i
];
1179 tmp
= getenv (tmp
+ 1);
1180 /* Note that `access' can lie to us if the directory resides on a
1181 read-only filesystem, like CD-ROM or a write-protected floppy.
1182 The only way to be really sure is to actually create a file and
1183 see if it succeeds. But I think that's too much to ask. */
1184 if (tmp
&& _access (tmp
, D_OK
) == 0)
1186 char * var
= alloca (strlen (tmp
) + 8);
1187 sprintf (var
, "TMPDIR=%s", tmp
);
1188 _putenv (strdup (var
));
1195 Fcons (build_string ("no usable temporary directories found!!"),
1197 "While setting TMPDIR: ");
1199 /* Check for environment variables and use registry settings if they
1200 don't exist. Fallback on default values where applicable. */
1205 char locale_name
[32];
1206 struct stat ignored
;
1207 char default_home
[MAX_PATH
];
1209 static const struct env_entry
1216 {"PRELOAD_WINSOCK", NULL
},
1217 {"emacs_dir", "C:/emacs"},
1218 {"EMACSLOADPATH", "%emacs_dir%/site-lisp;%emacs_dir%/../site-lisp;%emacs_dir%/lisp;%emacs_dir%/leim"},
1219 {"SHELL", "%emacs_dir%/bin/cmdproxy.exe"},
1220 {"EMACSDATA", "%emacs_dir%/etc"},
1221 {"EMACSPATH", "%emacs_dir%/bin"},
1222 /* We no longer set INFOPATH because Info-default-directory-list
1224 /* {"INFOPATH", "%emacs_dir%/info"}, */
1225 {"EMACSDOC", "%emacs_dir%/etc"},
1230 #define N_ENV_VARS sizeof(dflt_envvars)/sizeof(dflt_envvars[0])
1232 /* We need to copy dflt_envvars[] and work on the copy because we
1233 don't want the dumped Emacs to inherit the values of
1234 environment variables we saw during dumping (which could be on
1235 a different system). The defaults above must be left intact. */
1236 struct env_entry env_vars
[N_ENV_VARS
];
1238 for (i
= 0; i
< N_ENV_VARS
; i
++)
1239 env_vars
[i
] = dflt_envvars
[i
];
1241 /* For backwards compatibility, check if a .emacs file exists in C:/
1242 If not, then we can try to default to the appdata directory under the
1243 user's profile, which is more likely to be writable. */
1244 if (stat ("C:/.emacs", &ignored
) < 0)
1246 HRESULT profile_result
;
1247 /* Dynamically load ShGetFolderPath, as it won't exist on versions
1248 of Windows 95 and NT4 that have not been updated to include
1249 MSIE 5. Also we don't link with shell32.dll by default. */
1250 HMODULE shell32_dll
;
1251 ShGetFolderPath_fn get_folder_path
;
1252 shell32_dll
= GetModuleHandle ("shell32.dll");
1253 get_folder_path
= (ShGetFolderPath_fn
)
1254 GetProcAddress (shell32_dll
, "SHGetFolderPathA");
1256 if (get_folder_path
!= NULL
)
1258 profile_result
= get_folder_path (NULL
, CSIDL_APPDATA
, NULL
,
1261 /* If we can't get the appdata dir, revert to old behaviour. */
1262 if (profile_result
== S_OK
)
1263 env_vars
[0].def_value
= default_home
;
1266 /* Unload shell32.dll, it is not needed anymore. */
1267 FreeLibrary (shell32_dll
);
1270 /* Get default locale info and use it for LANG. */
1271 if (GetLocaleInfo (LOCALE_USER_DEFAULT
,
1272 LOCALE_SABBREVLANGNAME
| LOCALE_USE_CP_ACP
,
1273 locale_name
, sizeof (locale_name
)))
1275 for (i
= 0; i
< N_ENV_VARS
; i
++)
1277 if (strcmp (env_vars
[i
].name
, "LANG") == 0)
1279 env_vars
[i
].def_value
= locale_name
;
1285 #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
1287 /* Treat emacs_dir specially: set it unconditionally based on our
1288 location, if it appears that we are running from the bin subdir
1289 of a standard installation. */
1292 char modname
[MAX_PATH
];
1294 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
1296 if ((p
= strrchr (modname
, '\\')) == NULL
)
1300 if ((p
= strrchr (modname
, '\\')) && stricmp (p
, "\\bin") == 0)
1302 char buf
[SET_ENV_BUF_SIZE
];
1305 for (p
= modname
; *p
; p
++)
1306 if (*p
== '\\') *p
= '/';
1308 _snprintf (buf
, sizeof(buf
)-1, "emacs_dir=%s", modname
);
1309 _putenv (strdup (buf
));
1311 /* Handle running emacs from the build directory: src/oo-spd/i386/ */
1313 /* FIXME: should use substring of get_emacs_configuration ().
1314 But I don't think the Windows build supports alpha, mips etc
1315 anymore, so have taken the easy option for now. */
1316 else if (p
&& stricmp (p
, "\\i386") == 0)
1319 p
= strrchr (modname
, '\\');
1323 p
= strrchr (modname
, '\\');
1324 if (p
&& stricmp (p
, "\\src") == 0)
1326 char buf
[SET_ENV_BUF_SIZE
];
1329 for (p
= modname
; *p
; p
++)
1330 if (*p
== '\\') *p
= '/';
1332 _snprintf (buf
, sizeof(buf
)-1, "emacs_dir=%s", modname
);
1333 _putenv (strdup (buf
));
1339 for (i
= 0; i
< N_ENV_VARS
; i
++)
1341 if (!getenv (env_vars
[i
].name
))
1345 if ((lpval
= w32_get_resource (env_vars
[i
].name
, &dwType
)) == NULL
1346 /* Also ignore empty environment variables. */
1349 if (lpval
) xfree (lpval
);
1350 lpval
= env_vars
[i
].def_value
;
1351 dwType
= REG_EXPAND_SZ
;
1357 char buf1
[SET_ENV_BUF_SIZE
], buf2
[SET_ENV_BUF_SIZE
];
1359 if (dwType
== REG_EXPAND_SZ
)
1360 ExpandEnvironmentStrings ((LPSTR
) lpval
, buf1
, sizeof(buf1
));
1361 else if (dwType
== REG_SZ
)
1362 strcpy (buf1
, lpval
);
1363 if (dwType
== REG_EXPAND_SZ
|| dwType
== REG_SZ
)
1365 _snprintf (buf2
, sizeof(buf2
)-1, "%s=%s", env_vars
[i
].name
,
1367 _putenv (strdup (buf2
));
1377 /* Rebuild system configuration to reflect invoking system. */
1378 Vsystem_configuration
= build_string (EMACS_CONFIGURATION
);
1380 /* Another special case: on NT, the PATH variable is actually named
1381 "Path" although cmd.exe (perhaps NT itself) arranges for
1382 environment variable lookup and setting to be case insensitive.
1383 However, Emacs assumes a fully case sensitive environment, so we
1384 need to change "Path" to "PATH" to match the expectations of
1385 various elisp packages. We do this by the sneaky method of
1386 modifying the string in the C runtime environ entry.
1388 The same applies to COMSPEC. */
1392 for (envp
= environ
; *envp
; envp
++)
1393 if (_strnicmp (*envp
, "PATH=", 5) == 0)
1394 memcpy (*envp
, "PATH=", 5);
1395 else if (_strnicmp (*envp
, "COMSPEC=", 8) == 0)
1396 memcpy (*envp
, "COMSPEC=", 8);
1399 /* Remember the initial working directory for getwd, then make the
1400 real wd be the location of emacs.exe to avoid conflicts when
1401 renaming or deleting directories. (We also don't call chdir when
1402 running subprocesses for the same reason.) */
1403 if (!GetCurrentDirectory (MAXPATHLEN
, startup_dir
))
1408 static char modname
[MAX_PATH
];
1410 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
1412 if ((p
= strrchr (modname
, '\\')) == NULL
)
1416 SetCurrentDirectory (modname
);
1418 /* Ensure argv[0] has the full path to Emacs. */
1423 /* Determine if there is a middle mouse button, to allow parse_button
1424 to decide whether right mouse events should be mouse-2 or
1426 w32_num_mouse_buttons
= GetSystemMetrics (SM_CMOUSEBUTTONS
);
1432 emacs_root_dir (void)
1434 static char root_dir
[FILENAME_MAX
];
1437 p
= getenv ("emacs_dir");
1440 strcpy (root_dir
, p
);
1441 root_dir
[parse_root (root_dir
, NULL
)] = '\0';
1442 dostounix_filename (root_dir
);
1446 /* We don't have scripts to automatically determine the system configuration
1447 for Emacs before it's compiled, and we don't want to have to make the
1448 user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
1452 get_emacs_configuration (void)
1454 char *arch
, *oem
, *os
;
1456 static char configuration_buffer
[32];
1458 /* Determine the processor type. */
1459 switch (get_processor_type ())
1462 #ifdef PROCESSOR_INTEL_386
1463 case PROCESSOR_INTEL_386
:
1464 case PROCESSOR_INTEL_486
:
1465 case PROCESSOR_INTEL_PENTIUM
:
1470 #ifdef PROCESSOR_MIPS_R2000
1471 case PROCESSOR_MIPS_R2000
:
1472 case PROCESSOR_MIPS_R3000
:
1473 case PROCESSOR_MIPS_R4000
:
1478 #ifdef PROCESSOR_ALPHA_21064
1479 case PROCESSOR_ALPHA_21064
:
1489 /* Use the OEM field to reflect the compiler/library combination. */
1491 #define COMPILER_NAME "msvc"
1494 #define COMPILER_NAME "mingw"
1496 #define COMPILER_NAME "unknown"
1499 oem
= COMPILER_NAME
;
1501 switch (osinfo_cache
.dwPlatformId
) {
1502 case VER_PLATFORM_WIN32_NT
:
1504 build_num
= osinfo_cache
.dwBuildNumber
;
1506 case VER_PLATFORM_WIN32_WINDOWS
:
1507 if (osinfo_cache
.dwMinorVersion
== 0) {
1512 build_num
= LOWORD (osinfo_cache
.dwBuildNumber
);
1514 case VER_PLATFORM_WIN32s
:
1515 /* Not supported, should not happen. */
1517 build_num
= LOWORD (osinfo_cache
.dwBuildNumber
);
1525 if (osinfo_cache
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
1526 sprintf (configuration_buffer
, "%s-%s-%s%d.%d.%d", arch
, oem
, os
,
1527 get_w32_major_version (), get_w32_minor_version (), build_num
);
1529 sprintf (configuration_buffer
, "%s-%s-%s.%d", arch
, oem
, os
, build_num
);
1532 return configuration_buffer
;
1536 get_emacs_configuration_options (void)
1538 static char options_buffer
[256];
1540 /* Work out the effective configure options for this build. */
1542 #define COMPILER_VERSION "--with-msvc (%d.%02d)", _MSC_VER / 100, _MSC_VER % 100
1545 #define COMPILER_VERSION "--with-gcc (%d.%d)", __GNUC__, __GNUC_MINOR__
1547 #define COMPILER_VERSION ""
1551 sprintf (options_buffer
, COMPILER_VERSION
);
1553 strcat (options_buffer
, " --no-opt");
1556 strcat (options_buffer
, " --cflags");
1557 strcat (options_buffer
, USER_CFLAGS
);
1560 strcat (options_buffer
, " --ldflags");
1561 strcat (options_buffer
, USER_LDFLAGS
);
1563 return options_buffer
;
1567 #include <sys/timeb.h>
1569 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
1571 gettimeofday (struct timeval
*tv
, struct timezone
*tz
)
1576 tv
->tv_sec
= tb
.time
;
1577 tv
->tv_usec
= tb
.millitm
* 1000L;
1580 tz
->tz_minuteswest
= tb
.timezone
; /* minutes west of Greenwich */
1581 tz
->tz_dsttime
= tb
.dstflag
; /* type of dst correction */
1585 /* ------------------------------------------------------------------------- */
1586 /* IO support and wrapper functions for W32 API. */
1587 /* ------------------------------------------------------------------------- */
1589 /* Place a wrapper around the MSVC version of ctime. It returns NULL
1590 on network directories, so we handle that case here.
1591 (Ulrich Leodolter, 1/11/95). */
1593 sys_ctime (const time_t *t
)
1595 char *str
= (char *) ctime (t
);
1596 return (str
? str
: "Sun Jan 01 00:00:00 1970");
1599 /* Emulate sleep...we could have done this with a define, but that
1600 would necessitate including windows.h in the files that used it.
1601 This is much easier. */
1603 sys_sleep (int seconds
)
1605 Sleep (seconds
* 1000);
1608 /* Internal MSVC functions for low-level descriptor munging */
1609 extern int __cdecl
_set_osfhnd (int fd
, long h
);
1610 extern int __cdecl
_free_osfhnd (int fd
);
1612 /* parallel array of private info on file handles */
1613 filedesc fd_info
[ MAXDESC
];
1615 typedef struct volume_info_data
{
1616 struct volume_info_data
* next
;
1618 /* time when info was obtained */
1621 /* actual volume info */
1630 /* Global referenced by various functions. */
1631 static volume_info_data volume_info
;
1633 /* Vector to indicate which drives are local and fixed (for which cached
1634 data never expires). */
1635 static BOOL fixed_drives
[26];
1637 /* Consider cached volume information to be stale if older than 10s,
1638 at least for non-local drives. Info for fixed drives is never stale. */
1639 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
1640 #define VOLINFO_STILL_VALID( root_dir, info ) \
1641 ( ( isalpha (root_dir[0]) && \
1642 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
1643 || GetTickCount () - info->timestamp < 10000 )
1645 /* Cache support functions. */
1647 /* Simple linked list with linear search is sufficient. */
1648 static volume_info_data
*volume_cache
= NULL
;
1650 static volume_info_data
*
1651 lookup_volume_info (char * root_dir
)
1653 volume_info_data
* info
;
1655 for (info
= volume_cache
; info
; info
= info
->next
)
1656 if (stricmp (info
->root_dir
, root_dir
) == 0)
1662 add_volume_info (char * root_dir
, volume_info_data
* info
)
1664 info
->root_dir
= xstrdup (root_dir
);
1665 info
->next
= volume_cache
;
1666 volume_cache
= info
;
1670 /* Wrapper for GetVolumeInformation, which uses caching to avoid
1671 performance penalty (~2ms on 486 for local drives, 7.5ms for local
1672 cdrom drive, ~5-10ms or more for remote drives on LAN). */
1674 GetCachedVolumeInformation (char * root_dir
)
1676 volume_info_data
* info
;
1677 char default_root
[ MAX_PATH
];
1679 /* NULL for root_dir means use root from current directory. */
1680 if (root_dir
== NULL
)
1682 if (GetCurrentDirectory (MAX_PATH
, default_root
) == 0)
1684 parse_root (default_root
, &root_dir
);
1686 root_dir
= default_root
;
1689 /* Local fixed drives can be cached permanently. Removable drives
1690 cannot be cached permanently, since the volume name and serial
1691 number (if nothing else) can change. Remote drives should be
1692 treated as if they are removable, since there is no sure way to
1693 tell whether they are or not. Also, the UNC association of drive
1694 letters mapped to remote volumes can be changed at any time (even
1695 by other processes) without notice.
1697 As a compromise, so we can benefit from caching info for remote
1698 volumes, we use a simple expiry mechanism to invalidate cache
1699 entries that are more than ten seconds old. */
1702 /* No point doing this, because WNetGetConnection is even slower than
1703 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
1704 GetDriveType is about the only call of this type which does not
1705 involve network access, and so is extremely quick). */
1707 /* Map drive letter to UNC if remote. */
1708 if ( isalpha( root_dir
[0] ) && !fixed
[ DRIVE_INDEX( root_dir
[0] ) ] )
1710 char remote_name
[ 256 ];
1711 char drive
[3] = { root_dir
[0], ':' };
1713 if (WNetGetConnection (drive
, remote_name
, sizeof (remote_name
))
1715 /* do something */ ;
1719 info
= lookup_volume_info (root_dir
);
1721 if (info
== NULL
|| ! VOLINFO_STILL_VALID (root_dir
, info
))
1729 /* Info is not cached, or is stale. */
1730 if (!GetVolumeInformation (root_dir
,
1731 name
, sizeof (name
),
1735 type
, sizeof (type
)))
1738 /* Cache the volume information for future use, overwriting existing
1739 entry if present. */
1742 info
= (volume_info_data
*) xmalloc (sizeof (volume_info_data
));
1743 add_volume_info (root_dir
, info
);
1751 info
->name
= xstrdup (name
);
1752 info
->serialnum
= serialnum
;
1753 info
->maxcomp
= maxcomp
;
1754 info
->flags
= flags
;
1755 info
->type
= xstrdup (type
);
1756 info
->timestamp
= GetTickCount ();
1762 /* Get information on the volume where name is held; set path pointer to
1763 start of pathname in name (past UNC header\volume header if present). */
1765 get_volume_info (const char * name
, const char ** pPath
)
1767 char temp
[MAX_PATH
];
1768 char *rootname
= NULL
; /* default to current volume */
1769 volume_info_data
* info
;
1774 /* find the root name of the volume if given */
1775 if (isalpha (name
[0]) && name
[1] == ':')
1783 else if (IS_DIRECTORY_SEP (name
[0]) && IS_DIRECTORY_SEP (name
[1]))
1790 if (IS_DIRECTORY_SEP (*name
) && --slashes
== 0)
1803 info
= GetCachedVolumeInformation (rootname
);
1806 /* Set global referenced by other functions. */
1807 volume_info
= *info
;
1813 /* Determine if volume is FAT format (ie. only supports short 8.3
1814 names); also set path pointer to start of pathname in name. */
1816 is_fat_volume (const char * name
, const char ** pPath
)
1818 if (get_volume_info (name
, pPath
))
1819 return (volume_info
.maxcomp
== 12);
1823 /* Map filename to a valid 8.3 name if necessary. */
1825 map_w32_filename (const char * name
, const char ** pPath
)
1827 static char shortname
[MAX_PATH
];
1828 char * str
= shortname
;
1831 const char * save_name
= name
;
1833 if (strlen (name
) >= MAX_PATH
)
1835 /* Return a filename which will cause callers to fail. */
1836 strcpy (shortname
, "?");
1840 if (is_fat_volume (name
, (const char **)&path
)) /* truncate to 8.3 */
1842 register int left
= 8; /* maximum number of chars in part */
1843 register int extn
= 0; /* extension added? */
1844 register int dots
= 2; /* maximum number of dots allowed */
1847 *str
++ = *name
++; /* skip past UNC header */
1849 while ((c
= *name
++))
1856 extn
= 0; /* reset extension flags */
1857 dots
= 2; /* max 2 dots */
1858 left
= 8; /* max length 8 for main part */
1862 extn
= 0; /* reset extension flags */
1863 dots
= 2; /* max 2 dots */
1864 left
= 8; /* max length 8 for main part */
1869 /* Convert path components of the form .xxx to _xxx,
1870 but leave . and .. as they are. This allows .emacs
1871 to be read as _emacs, for example. */
1875 IS_DIRECTORY_SEP (*name
))
1890 extn
= 1; /* we've got an extension */
1891 left
= 3; /* 3 chars in extension */
1895 /* any embedded dots after the first are converted to _ */
1900 case '#': /* don't lose these, they're important */
1902 str
[-1] = c
; /* replace last character of part */
1907 *str
++ = tolower (c
); /* map to lower case (looks nicer) */
1909 dots
= 0; /* started a path component */
1918 strcpy (shortname
, name
);
1919 unixtodos_filename (shortname
);
1923 *pPath
= shortname
+ (path
- save_name
);
1929 is_exec (const char * name
)
1931 char * p
= strrchr (name
, '.');
1934 && (stricmp (p
, ".exe") == 0 ||
1935 stricmp (p
, ".com") == 0 ||
1936 stricmp (p
, ".bat") == 0 ||
1937 stricmp (p
, ".cmd") == 0));
1940 /* Emulate the Unix directory procedures opendir, closedir,
1941 and readdir. We can't use the procedures supplied in sysdep.c,
1942 so we provide them here. */
1944 struct direct dir_static
; /* simulated directory contents */
1945 static HANDLE dir_find_handle
= INVALID_HANDLE_VALUE
;
1946 static int dir_is_fat
;
1947 static char dir_pathname
[MAXPATHLEN
+1];
1948 static WIN32_FIND_DATA dir_find_data
;
1950 /* Support shares on a network resource as subdirectories of a read-only
1952 static HANDLE wnet_enum_handle
= INVALID_HANDLE_VALUE
;
1953 HANDLE
open_unc_volume (const char *);
1954 char *read_unc_volume (HANDLE
, char *, int);
1955 void close_unc_volume (HANDLE
);
1958 opendir (char *filename
)
1962 /* Opening is done by FindFirstFile. However, a read is inherent to
1963 this operation, so we defer the open until read time. */
1965 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
1967 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
1970 if (is_unc_volume (filename
))
1972 wnet_enum_handle
= open_unc_volume (filename
);
1973 if (wnet_enum_handle
== INVALID_HANDLE_VALUE
)
1977 if (!(dirp
= (DIR *) malloc (sizeof (DIR))))
1984 strncpy (dir_pathname
, map_w32_filename (filename
, NULL
), MAXPATHLEN
);
1985 dir_pathname
[MAXPATHLEN
] = '\0';
1986 dir_is_fat
= is_fat_volume (filename
, NULL
);
1992 closedir (DIR *dirp
)
1994 /* If we have a find-handle open, close it. */
1995 if (dir_find_handle
!= INVALID_HANDLE_VALUE
)
1997 FindClose (dir_find_handle
);
1998 dir_find_handle
= INVALID_HANDLE_VALUE
;
2000 else if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2002 close_unc_volume (wnet_enum_handle
);
2003 wnet_enum_handle
= INVALID_HANDLE_VALUE
;
2005 xfree ((char *) dirp
);
2011 int downcase
= !NILP (Vw32_downcase_file_names
);
2013 if (wnet_enum_handle
!= INVALID_HANDLE_VALUE
)
2015 if (!read_unc_volume (wnet_enum_handle
,
2016 dir_find_data
.cFileName
,
2020 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
2021 else if (dir_find_handle
== INVALID_HANDLE_VALUE
)
2023 char filename
[MAXNAMLEN
+ 3];
2026 strcpy (filename
, dir_pathname
);
2027 ln
= strlen (filename
) - 1;
2028 if (!IS_DIRECTORY_SEP (filename
[ln
]))
2029 strcat (filename
, "\\");
2030 strcat (filename
, "*");
2032 dir_find_handle
= FindFirstFile (filename
, &dir_find_data
);
2034 if (dir_find_handle
== INVALID_HANDLE_VALUE
)
2039 if (!FindNextFile (dir_find_handle
, &dir_find_data
))
2043 /* Emacs never uses this value, so don't bother making it match
2044 value returned by stat(). */
2045 dir_static
.d_ino
= 1;
2047 strcpy (dir_static
.d_name
, dir_find_data
.cFileName
);
2049 /* If the file name in cFileName[] includes `?' characters, it means
2050 the original file name used characters that cannot be represented
2051 by the current ANSI codepage. To avoid total lossage, retrieve
2052 the short 8+3 alias of the long file name. */
2053 if (_mbspbrk (dir_static
.d_name
, "?"))
2055 strcpy (dir_static
.d_name
, dir_find_data
.cAlternateFileName
);
2056 downcase
= 1; /* 8+3 aliases are returned in all caps */
2058 dir_static
.d_namlen
= strlen (dir_static
.d_name
);
2059 dir_static
.d_reclen
= sizeof (struct direct
) - MAXNAMLEN
+ 3 +
2060 dir_static
.d_namlen
- dir_static
.d_namlen
% 4;
2062 /* If the file name in cFileName[] includes `?' characters, it means
2063 the original file name used characters that cannot be represented
2064 by the current ANSI codepage. To avoid total lossage, retrieve
2065 the short 8+3 alias of the long file name. */
2066 if (_mbspbrk (dir_find_data
.cFileName
, "?"))
2068 strcpy (dir_static
.d_name
, dir_find_data
.cAlternateFileName
);
2069 /* 8+3 aliases are returned in all caps, which could break
2070 various alists that look at filenames' extensions. */
2074 strcpy (dir_static
.d_name
, dir_find_data
.cFileName
);
2075 dir_static
.d_namlen
= strlen (dir_static
.d_name
);
2077 _strlwr (dir_static
.d_name
);
2081 for (p
= dir_static
.d_name
; *p
; p
++)
2082 if (*p
>= 'a' && *p
<= 'z')
2085 _strlwr (dir_static
.d_name
);
2092 open_unc_volume (const char *path
)
2098 nr
.dwScope
= RESOURCE_GLOBALNET
;
2099 nr
.dwType
= RESOURCETYPE_DISK
;
2100 nr
.dwDisplayType
= RESOURCEDISPLAYTYPE_SERVER
;
2101 nr
.dwUsage
= RESOURCEUSAGE_CONTAINER
;
2102 nr
.lpLocalName
= NULL
;
2103 nr
.lpRemoteName
= (LPSTR
)map_w32_filename (path
, NULL
);
2104 nr
.lpComment
= NULL
;
2105 nr
.lpProvider
= NULL
;
2107 result
= WNetOpenEnum(RESOURCE_GLOBALNET
, RESOURCETYPE_DISK
,
2108 RESOURCEUSAGE_CONNECTABLE
, &nr
, &henum
);
2110 if (result
== NO_ERROR
)
2113 return INVALID_HANDLE_VALUE
;
2117 read_unc_volume (HANDLE henum
, char *readbuf
, int size
)
2121 DWORD bufsize
= 512;
2126 buffer
= alloca (bufsize
);
2127 result
= WNetEnumResource (wnet_enum_handle
, &count
, buffer
, &bufsize
);
2128 if (result
!= NO_ERROR
)
2131 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
2132 ptr
= ((LPNETRESOURCE
) buffer
)->lpRemoteName
;
2134 while (*ptr
&& !IS_DIRECTORY_SEP (*ptr
)) ptr
++;
2137 strncpy (readbuf
, ptr
, size
);
2142 close_unc_volume (HANDLE henum
)
2144 if (henum
!= INVALID_HANDLE_VALUE
)
2145 WNetCloseEnum (henum
);
2149 unc_volume_file_attributes (const char *path
)
2154 henum
= open_unc_volume (path
);
2155 if (henum
== INVALID_HANDLE_VALUE
)
2158 attrs
= FILE_ATTRIBUTE_READONLY
| FILE_ATTRIBUTE_DIRECTORY
;
2160 close_unc_volume (henum
);
2165 /* Ensure a network connection is authenticated. */
2167 logon_network_drive (const char *path
)
2169 NETRESOURCE resource
;
2170 char share
[MAX_PATH
];
2174 sprintf (drive
, "%c:\\", path
[0]);
2176 /* Only logon to networked drives. */
2177 if ((!IS_DIRECTORY_SEP (path
[0]) || !IS_DIRECTORY_SEP (path
[1]))
2178 && GetDriveType (drive
) != DRIVE_REMOTE
)
2182 strncpy (share
, path
, MAX_PATH
);
2183 /* Truncate to just server and share name. */
2184 for (i
= 2; i
< MAX_PATH
; i
++)
2186 if (IS_DIRECTORY_SEP (share
[i
]) && ++n_slashes
> 3)
2193 resource
.dwType
= RESOURCETYPE_DISK
;
2194 resource
.lpLocalName
= NULL
;
2195 resource
.lpRemoteName
= share
;
2196 resource
.lpProvider
= NULL
;
2198 WNetAddConnection2 (&resource
, NULL
, NULL
, CONNECT_INTERACTIVE
);
2201 /* Shadow some MSVC runtime functions to map requests for long filenames
2202 to reasonable short names if necessary. This was originally added to
2203 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
2207 sys_access (const char * path
, int mode
)
2211 /* MSVC implementation doesn't recognize D_OK. */
2212 path
= map_w32_filename (path
, NULL
);
2213 if (is_unc_volume (path
))
2215 attributes
= unc_volume_file_attributes (path
);
2216 if (attributes
== -1) {
2221 else if ((attributes
= GetFileAttributes (path
)) == -1)
2223 /* Should try mapping GetLastError to errno; for now just indicate
2224 that path doesn't exist. */
2228 if ((mode
& X_OK
) != 0 && !is_exec (path
))
2233 if ((mode
& W_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_READONLY
) != 0)
2238 if ((mode
& D_OK
) != 0 && (attributes
& FILE_ATTRIBUTE_DIRECTORY
) == 0)
2247 sys_chdir (const char * path
)
2249 return _chdir (map_w32_filename (path
, NULL
));
2253 sys_chmod (const char * path
, int mode
)
2255 return _chmod (map_w32_filename (path
, NULL
), mode
);
2259 sys_chown (const char *path
, uid_t owner
, gid_t group
)
2261 if (sys_chmod (path
, S_IREAD
) == -1) /* check if file exists */
2267 sys_creat (const char * path
, int mode
)
2269 return _creat (map_w32_filename (path
, NULL
), mode
);
2273 sys_fopen(const char * path
, const char * mode
)
2277 const char * mode_save
= mode
;
2279 /* Force all file handles to be non-inheritable. This is necessary to
2280 ensure child processes don't unwittingly inherit handles that might
2281 prevent future file access. */
2285 else if (mode
[0] == 'w' || mode
[0] == 'a')
2286 oflag
= O_WRONLY
| O_CREAT
| O_TRUNC
;
2290 /* Only do simplistic option parsing. */
2294 oflag
&= ~(O_RDONLY
| O_WRONLY
);
2297 else if (mode
[0] == 'b')
2302 else if (mode
[0] == 't')
2309 fd
= _open (map_w32_filename (path
, NULL
), oflag
| _O_NOINHERIT
, 0644);
2313 return _fdopen (fd
, mode_save
);
2316 /* This only works on NTFS volumes, but is useful to have. */
2318 sys_link (const char * old
, const char * new)
2322 char oldname
[MAX_PATH
], newname
[MAX_PATH
];
2324 if (old
== NULL
|| new == NULL
)
2330 strcpy (oldname
, map_w32_filename (old
, NULL
));
2331 strcpy (newname
, map_w32_filename (new, NULL
));
2333 fileh
= CreateFile (oldname
, 0, 0, NULL
, OPEN_EXISTING
,
2334 FILE_FLAG_BACKUP_SEMANTICS
, NULL
);
2335 if (fileh
!= INVALID_HANDLE_VALUE
)
2339 /* Confusingly, the "alternate" stream name field does not apply
2340 when restoring a hard link, and instead contains the actual
2341 stream data for the link (ie. the name of the link to create).
2342 The WIN32_STREAM_ID structure before the cStreamName field is
2343 the stream header, which is then immediately followed by the
2347 WIN32_STREAM_ID wid
;
2348 WCHAR wbuffer
[MAX_PATH
]; /* extra space for link name */
2351 wlen
= MultiByteToWideChar (CP_ACP
, MB_PRECOMPOSED
, newname
, -1,
2352 data
.wid
.cStreamName
, MAX_PATH
);
2355 LPVOID context
= NULL
;
2358 data
.wid
.dwStreamId
= BACKUP_LINK
;
2359 data
.wid
.dwStreamAttributes
= 0;
2360 data
.wid
.Size
.LowPart
= wlen
* sizeof(WCHAR
);
2361 data
.wid
.Size
.HighPart
= 0;
2362 data
.wid
.dwStreamNameSize
= 0;
2364 if (BackupWrite (fileh
, (LPBYTE
)&data
,
2365 offsetof (WIN32_STREAM_ID
, cStreamName
)
2366 + data
.wid
.Size
.LowPart
,
2367 &wbytes
, FALSE
, FALSE
, &context
)
2368 && BackupWrite (fileh
, NULL
, 0, &wbytes
, TRUE
, FALSE
, &context
))
2375 /* Should try mapping GetLastError to errno; for now just
2376 indicate a general error (eg. links not supported). */
2377 errno
= EINVAL
; // perhaps EMLINK?
2381 CloseHandle (fileh
);
2390 sys_mkdir (const char * path
)
2392 return _mkdir (map_w32_filename (path
, NULL
));
2395 /* Because of long name mapping issues, we need to implement this
2396 ourselves. Also, MSVC's _mktemp returns NULL when it can't generate
2397 a unique name, instead of setting the input template to an empty
2400 Standard algorithm seems to be use pid or tid with a letter on the
2401 front (in place of the 6 X's) and cycle through the letters to find a
2402 unique name. We extend that to allow any reasonable character as the
2403 first of the 6 X's. */
2405 sys_mktemp (char * template)
2409 unsigned uid
= GetCurrentThreadId ();
2410 static char first_char
[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
2412 if (template == NULL
)
2414 p
= template + strlen (template);
2416 /* replace up to the last 5 X's with uid in decimal */
2417 while (--p
>= template && p
[0] == 'X' && --i
>= 0)
2419 p
[0] = '0' + uid
% 10;
2423 if (i
< 0 && p
[0] == 'X')
2428 int save_errno
= errno
;
2429 p
[0] = first_char
[i
];
2430 if (sys_access (template, 0) < 0)
2436 while (++i
< sizeof (first_char
));
2439 /* Template is badly formed or else we can't generate a unique name,
2440 so return empty string */
2446 sys_open (const char * path
, int oflag
, int mode
)
2448 const char* mpath
= map_w32_filename (path
, NULL
);
2449 /* Try to open file without _O_CREAT, to be able to write to hidden
2450 and system files. Force all file handles to be
2452 int res
= _open (mpath
, (oflag
& ~_O_CREAT
) | _O_NOINHERIT
, mode
);
2455 return _open (mpath
, oflag
| _O_NOINHERIT
, mode
);
2459 sys_rename (const char * oldname
, const char * newname
)
2462 char temp
[MAX_PATH
];
2464 /* MoveFile on Windows 95 doesn't correctly change the short file name
2465 alias in a number of circumstances (it is not easy to predict when
2466 just by looking at oldname and newname, unfortunately). In these
2467 cases, renaming through a temporary name avoids the problem.
2469 A second problem on Windows 95 is that renaming through a temp name when
2470 newname is uppercase fails (the final long name ends up in
2471 lowercase, although the short alias might be uppercase) UNLESS the
2472 long temp name is not 8.3.
2474 So, on Windows 95 we always rename through a temp name, and we make sure
2475 the temp name has a long extension to ensure correct renaming. */
2477 strcpy (temp
, map_w32_filename (oldname
, NULL
));
2479 if (os_subtype
== OS_WIN95
)
2485 oldname
= map_w32_filename (oldname
, NULL
);
2486 if (o
= strrchr (oldname
, '\\'))
2489 o
= (char *) oldname
;
2491 if (p
= strrchr (temp
, '\\'))
2498 /* Force temp name to require a manufactured 8.3 alias - this
2499 seems to make the second rename work properly. */
2500 sprintf (p
, "_.%s.%u", o
, i
);
2502 result
= rename (oldname
, temp
);
2504 /* This loop must surely terminate! */
2505 while (result
< 0 && errno
== EEXIST
);
2510 /* Emulate Unix behaviour - newname is deleted if it already exists
2511 (at least if it is a file; don't do this for directories).
2513 Since we mustn't do this if we are just changing the case of the
2514 file name (we would end up deleting the file we are trying to
2515 rename!), we let rename detect if the destination file already
2516 exists - that way we avoid the possible pitfalls of trying to
2517 determine ourselves whether two names really refer to the same
2518 file, which is not always possible in the general case. (Consider
2519 all the permutations of shared or subst'd drives, etc.) */
2521 newname
= map_w32_filename (newname
, NULL
);
2522 result
= rename (temp
, newname
);
2526 && _chmod (newname
, 0666) == 0
2527 && _unlink (newname
) == 0)
2528 result
= rename (temp
, newname
);
2534 sys_rmdir (const char * path
)
2536 return _rmdir (map_w32_filename (path
, NULL
));
2540 sys_unlink (const char * path
)
2542 path
= map_w32_filename (path
, NULL
);
2544 /* On Unix, unlink works without write permission. */
2545 _chmod (path
, 0666);
2546 return _unlink (path
);
2549 static FILETIME utc_base_ft
;
2550 static long double utc_base
;
2551 static int init
= 0;
2554 convert_time (FILETIME ft
)
2560 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
2569 st
.wMilliseconds
= 0;
2571 SystemTimeToFileTime (&st
, &utc_base_ft
);
2572 utc_base
= (long double) utc_base_ft
.dwHighDateTime
2573 * 4096.0L * 1024.0L * 1024.0L + utc_base_ft
.dwLowDateTime
;
2577 if (CompareFileTime (&ft
, &utc_base_ft
) < 0)
2580 ret
= (long double) ft
.dwHighDateTime
2581 * 4096.0L * 1024.0L * 1024.0L + ft
.dwLowDateTime
;
2583 return (time_t) (ret
* 1e-7L);
2587 convert_from_time_t (time_t time
, FILETIME
* pft
)
2593 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
2602 st
.wMilliseconds
= 0;
2604 SystemTimeToFileTime (&st
, &utc_base_ft
);
2605 utc_base
= (long double) utc_base_ft
.dwHighDateTime
2606 * 4096 * 1024 * 1024 + utc_base_ft
.dwLowDateTime
;
2610 /* time in 100ns units since 1-Jan-1601 */
2611 tmp
= (long double) time
* 1e7
+ utc_base
;
2612 pft
->dwHighDateTime
= (DWORD
) (tmp
/ (4096.0 * 1024 * 1024));
2613 pft
->dwLowDateTime
= (DWORD
) (tmp
- (4096.0 * 1024 * 1024) * pft
->dwHighDateTime
);
2617 /* No reason to keep this; faking inode values either by hashing or even
2618 using the file index from GetInformationByHandle, is not perfect and
2619 so by default Emacs doesn't use the inode values on Windows.
2620 Instead, we now determine file-truename correctly (except for
2621 possible drive aliasing etc). */
2623 /* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
2625 hashval (const unsigned char * str
)
2630 h
= (h
<< 4) + *str
++;
2636 /* Return the hash value of the canonical pathname, excluding the
2637 drive/UNC header, to get a hopefully unique inode number. */
2639 generate_inode_val (const char * name
)
2641 char fullname
[ MAX_PATH
];
2645 /* Get the truly canonical filename, if it exists. (Note: this
2646 doesn't resolve aliasing due to subst commands, or recognise hard
2648 if (!w32_get_long_filename ((char *)name
, fullname
, MAX_PATH
))
2651 parse_root (fullname
, &p
);
2652 /* Normal W32 filesystems are still case insensitive. */
2659 static PSECURITY_DESCRIPTOR
2660 get_file_security_desc (const char *fname
)
2662 PSECURITY_DESCRIPTOR psd
= NULL
;
2664 SECURITY_INFORMATION si
= OWNER_SECURITY_INFORMATION
2665 | GROUP_SECURITY_INFORMATION
/* | DACL_SECURITY_INFORMATION */ ;
2667 if (!get_file_security (fname
, si
, psd
, 0, &sd_len
))
2669 err
= GetLastError ();
2670 if (err
!= ERROR_INSUFFICIENT_BUFFER
)
2674 psd
= xmalloc (sd_len
);
2675 if (!get_file_security (fname
, si
, psd
, sd_len
, &sd_len
))
2687 unsigned n_subauthorities
;
2689 /* Use the last sub-authority value of the RID, the relative
2690 portion of the SID, as user/group ID. */
2691 n_subauthorities
= *get_sid_sub_authority_count (sid
);
2692 if (n_subauthorities
< 1)
2693 return 0; /* the "World" RID */
2694 return *get_sid_sub_authority (sid
, n_subauthorities
- 1);
2701 get_name_and_id (PSECURITY_DESCRIPTOR psd
, const char *fname
,
2702 int *id
, char *nm
, int what
)
2705 char machine
[MAX_COMPUTERNAME_LENGTH
+1];
2707 SID_NAME_USE ignore
;
2709 DWORD name_len
= sizeof (name
);
2711 DWORD domain_len
= sizeof(domain
);
2717 result
= get_security_descriptor_owner (psd
, &sid
, &dflt
);
2718 else if (what
== GID
)
2719 result
= get_security_descriptor_group (psd
, &sid
, &dflt
);
2723 if (!result
|| !is_valid_sid (sid
))
2727 /* If FNAME is a UNC, we need to lookup account on the
2728 specified machine. */
2729 if (IS_DIRECTORY_SEP (fname
[0]) && IS_DIRECTORY_SEP (fname
[1])
2730 && fname
[2] != '\0')
2735 for (s
= fname
+ 2, p
= machine
;
2736 *s
&& !IS_DIRECTORY_SEP (*s
); s
++, p
++)
2742 if (!lookup_account_sid (mp
, sid
, name
, &name_len
,
2743 domain
, &domain_len
, &ignore
)
2744 || name_len
> UNLEN
+1)
2748 *id
= get_rid (sid
);
2756 get_file_owner_and_group (
2757 PSECURITY_DESCRIPTOR psd
,
2761 int dflt_usr
= 0, dflt_grp
= 0;
2770 if (get_name_and_id (psd
, fname
, &st
->st_uid
, st
->st_uname
, UID
))
2772 if (get_name_and_id (psd
, fname
, &st
->st_gid
, st
->st_gname
, GID
))
2775 /* Consider files to belong to current user/group, if we cannot get
2776 more accurate information. */
2779 st
->st_uid
= dflt_passwd
.pw_uid
;
2780 strcpy (st
->st_uname
, dflt_passwd
.pw_name
);
2784 st
->st_gid
= dflt_passwd
.pw_gid
;
2785 strcpy (st
->st_gname
, dflt_group
.gr_name
);
2789 /* MSVC stat function can't cope with UNC names and has other bugs, so
2790 replace it with our own. This also allows us to calculate consistent
2791 inode values without hacks in the main Emacs code. */
2793 stat (const char * path
, struct stat
* buf
)
2796 WIN32_FIND_DATA wfd
;
2798 unsigned __int64 fake_inode
;
2801 int rootdir
= FALSE
;
2802 PSECURITY_DESCRIPTOR psd
= NULL
;
2804 if (path
== NULL
|| buf
== NULL
)
2810 name
= (char *) map_w32_filename (path
, &path
);
2811 /* Must be valid filename, no wild cards or other invalid
2812 characters. We use _mbspbrk to support multibyte strings that
2813 might look to strpbrk as if they included literal *, ?, and other
2814 characters mentioned below that are disallowed by Windows
2816 if (_mbspbrk (name
, "*?|<>\""))
2822 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
2823 r
= IS_DEVICE_SEP (name
[1]) ? &name
[2] : name
;
2824 if (IS_DIRECTORY_SEP (r
[0]) && r
[1] == '.' && r
[2] == '.' && r
[3] == '\0')
2829 /* Remove trailing directory separator, unless name is the root
2830 directory of a drive or UNC volume in which case ensure there
2831 is a trailing separator. */
2832 len
= strlen (name
);
2833 rootdir
= (path
>= name
+ len
- 1
2834 && (IS_DIRECTORY_SEP (*path
) || *path
== 0));
2835 name
= strcpy (alloca (len
+ 2), name
);
2837 if (is_unc_volume (name
))
2839 DWORD attrs
= unc_volume_file_attributes (name
);
2844 memset (&wfd
, 0, sizeof (wfd
));
2845 wfd
.dwFileAttributes
= attrs
;
2846 wfd
.ftCreationTime
= utc_base_ft
;
2847 wfd
.ftLastAccessTime
= utc_base_ft
;
2848 wfd
.ftLastWriteTime
= utc_base_ft
;
2849 strcpy (wfd
.cFileName
, name
);
2853 if (!IS_DIRECTORY_SEP (name
[len
-1]))
2854 strcat (name
, "\\");
2855 if (GetDriveType (name
) < 2)
2860 memset (&wfd
, 0, sizeof (wfd
));
2861 wfd
.dwFileAttributes
= FILE_ATTRIBUTE_DIRECTORY
;
2862 wfd
.ftCreationTime
= utc_base_ft
;
2863 wfd
.ftLastAccessTime
= utc_base_ft
;
2864 wfd
.ftLastWriteTime
= utc_base_ft
;
2865 strcpy (wfd
.cFileName
, name
);
2869 if (IS_DIRECTORY_SEP (name
[len
-1]))
2872 /* (This is hacky, but helps when doing file completions on
2873 network drives.) Optimize by using information available from
2874 active readdir if possible. */
2875 len
= strlen (dir_pathname
);
2876 if (IS_DIRECTORY_SEP (dir_pathname
[len
-1]))
2878 if (dir_find_handle
!= INVALID_HANDLE_VALUE
2879 && strnicmp (name
, dir_pathname
, len
) == 0
2880 && IS_DIRECTORY_SEP (name
[len
])
2881 && stricmp (name
+ len
+ 1, dir_static
.d_name
) == 0)
2883 /* This was the last entry returned by readdir. */
2884 wfd
= dir_find_data
;
2888 logon_network_drive (name
);
2890 fh
= FindFirstFile (name
, &wfd
);
2891 if (fh
== INVALID_HANDLE_VALUE
)
2900 if (!(NILP (Vw32_get_true_file_attributes
)
2901 || (EQ (Vw32_get_true_file_attributes
, Qlocal
) &&
2902 GetDriveType (name
) != DRIVE_FIXED
))
2903 /* No access rights required to get info. */
2904 && (fh
= CreateFile (name
, 0, 0, NULL
, OPEN_EXISTING
,
2905 FILE_FLAG_BACKUP_SEMANTICS
, NULL
))
2906 != INVALID_HANDLE_VALUE
)
2908 /* This is more accurate in terms of gettting the correct number
2909 of links, but is quite slow (it is noticeable when Emacs is
2910 making a list of file name completions). */
2911 BY_HANDLE_FILE_INFORMATION info
;
2913 if (GetFileInformationByHandle (fh
, &info
))
2915 buf
->st_nlink
= info
.nNumberOfLinks
;
2916 /* Might as well use file index to fake inode values, but this
2917 is not guaranteed to be unique unless we keep a handle open
2918 all the time (even then there are situations where it is
2919 not unique). Reputedly, there are at most 48 bits of info
2920 (on NTFS, presumably less on FAT). */
2921 fake_inode
= info
.nFileIndexHigh
;
2923 fake_inode
+= info
.nFileIndexLow
;
2931 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
2933 buf
->st_mode
= S_IFDIR
;
2937 switch (GetFileType (fh
))
2939 case FILE_TYPE_DISK
:
2940 buf
->st_mode
= S_IFREG
;
2942 case FILE_TYPE_PIPE
:
2943 buf
->st_mode
= S_IFIFO
;
2945 case FILE_TYPE_CHAR
:
2946 case FILE_TYPE_UNKNOWN
:
2948 buf
->st_mode
= S_IFCHR
;
2952 psd
= get_file_security_desc (name
);
2953 get_file_owner_and_group (psd
, name
, buf
);
2957 /* Don't bother to make this information more accurate. */
2958 buf
->st_mode
= (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
2963 get_file_owner_and_group (NULL
, name
, buf
);
2969 /* Not sure if there is any point in this. */
2970 if (!NILP (Vw32_generate_fake_inodes
))
2971 fake_inode
= generate_inode_val (name
);
2972 else if (fake_inode
== 0)
2974 /* For want of something better, try to make everything unique. */
2975 static DWORD gen_num
= 0;
2976 fake_inode
= ++gen_num
;
2980 /* MSVC defines _ino_t to be short; other libc's might not. */
2981 if (sizeof (buf
->st_ino
) == 2)
2982 buf
->st_ino
= fake_inode
^ (fake_inode
>> 16);
2984 buf
->st_ino
= fake_inode
;
2986 /* volume_info is set indirectly by map_w32_filename */
2987 buf
->st_dev
= volume_info
.serialnum
;
2988 buf
->st_rdev
= volume_info
.serialnum
;
2991 buf
->st_size
= wfd
.nFileSizeHigh
;
2992 buf
->st_size
<<= 32;
2993 buf
->st_size
+= wfd
.nFileSizeLow
;
2995 /* Convert timestamps to Unix format. */
2996 buf
->st_mtime
= convert_time (wfd
.ftLastWriteTime
);
2997 buf
->st_atime
= convert_time (wfd
.ftLastAccessTime
);
2998 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
2999 buf
->st_ctime
= convert_time (wfd
.ftCreationTime
);
3000 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
3002 /* determine rwx permissions */
3003 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
3004 permission
= S_IREAD
;
3006 permission
= S_IREAD
| S_IWRITE
;
3008 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3009 permission
|= S_IEXEC
;
3010 else if (is_exec (name
))
3011 permission
|= S_IEXEC
;
3013 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
3018 /* Provide fstat and utime as well as stat for consistent handling of
3021 fstat (int desc
, struct stat
* buf
)
3023 HANDLE fh
= (HANDLE
) _get_osfhandle (desc
);
3024 BY_HANDLE_FILE_INFORMATION info
;
3025 unsigned __int64 fake_inode
;
3028 switch (GetFileType (fh
) & ~FILE_TYPE_REMOTE
)
3030 case FILE_TYPE_DISK
:
3031 buf
->st_mode
= S_IFREG
;
3032 if (!GetFileInformationByHandle (fh
, &info
))
3038 case FILE_TYPE_PIPE
:
3039 buf
->st_mode
= S_IFIFO
;
3041 case FILE_TYPE_CHAR
:
3042 case FILE_TYPE_UNKNOWN
:
3044 buf
->st_mode
= S_IFCHR
;
3046 memset (&info
, 0, sizeof (info
));
3047 info
.dwFileAttributes
= 0;
3048 info
.ftCreationTime
= utc_base_ft
;
3049 info
.ftLastAccessTime
= utc_base_ft
;
3050 info
.ftLastWriteTime
= utc_base_ft
;
3053 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3054 buf
->st_mode
= S_IFDIR
;
3056 buf
->st_nlink
= info
.nNumberOfLinks
;
3057 /* Might as well use file index to fake inode values, but this
3058 is not guaranteed to be unique unless we keep a handle open
3059 all the time (even then there are situations where it is
3060 not unique). Reputedly, there are at most 48 bits of info
3061 (on NTFS, presumably less on FAT). */
3062 fake_inode
= info
.nFileIndexHigh
;
3064 fake_inode
+= info
.nFileIndexLow
;
3066 /* MSVC defines _ino_t to be short; other libc's might not. */
3067 if (sizeof (buf
->st_ino
) == 2)
3068 buf
->st_ino
= fake_inode
^ (fake_inode
>> 16);
3070 buf
->st_ino
= fake_inode
;
3072 /* Consider files to belong to current user.
3073 FIXME: this should use GetSecurityInfo API, but it is only
3074 available for _WIN32_WINNT >= 0x501. */
3075 buf
->st_uid
= dflt_passwd
.pw_uid
;
3076 buf
->st_gid
= dflt_passwd
.pw_gid
;
3077 strcpy (buf
->st_uname
, dflt_passwd
.pw_name
);
3078 strcpy (buf
->st_gname
, dflt_group
.gr_name
);
3080 buf
->st_dev
= info
.dwVolumeSerialNumber
;
3081 buf
->st_rdev
= info
.dwVolumeSerialNumber
;
3083 buf
->st_size
= info
.nFileSizeHigh
;
3084 buf
->st_size
<<= 32;
3085 buf
->st_size
+= info
.nFileSizeLow
;
3087 /* Convert timestamps to Unix format. */
3088 buf
->st_mtime
= convert_time (info
.ftLastWriteTime
);
3089 buf
->st_atime
= convert_time (info
.ftLastAccessTime
);
3090 if (buf
->st_atime
== 0) buf
->st_atime
= buf
->st_mtime
;
3091 buf
->st_ctime
= convert_time (info
.ftCreationTime
);
3092 if (buf
->st_ctime
== 0) buf
->st_ctime
= buf
->st_mtime
;
3094 /* determine rwx permissions */
3095 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
3096 permission
= S_IREAD
;
3098 permission
= S_IREAD
| S_IWRITE
;
3100 if (info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
3101 permission
|= S_IEXEC
;
3104 #if 0 /* no way of knowing the filename */
3105 char * p
= strrchr (name
, '.');
3107 (stricmp (p
, ".exe") == 0 ||
3108 stricmp (p
, ".com") == 0 ||
3109 stricmp (p
, ".bat") == 0 ||
3110 stricmp (p
, ".cmd") == 0))
3111 permission
|= S_IEXEC
;
3115 buf
->st_mode
|= permission
| (permission
>> 3) | (permission
>> 6);
3121 utime (const char *name
, struct utimbuf
*times
)
3123 struct utimbuf deftime
;
3130 deftime
.modtime
= deftime
.actime
= time (NULL
);
3134 /* Need write access to set times. */
3135 fh
= CreateFile (name
, GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
3136 0, OPEN_EXISTING
, 0, NULL
);
3139 convert_from_time_t (times
->actime
, &atime
);
3140 convert_from_time_t (times
->modtime
, &mtime
);
3141 if (!SetFileTime (fh
, NULL
, &atime
, &mtime
))
3159 /* Wrappers for winsock functions to map between our file descriptors
3160 and winsock's handles; also set h_errno for convenience.
3162 To allow Emacs to run on systems which don't have winsock support
3163 installed, we dynamically link to winsock on startup if present, and
3164 otherwise provide the minimum necessary functionality
3165 (eg. gethostname). */
3167 /* function pointers for relevant socket functions */
3168 int (PASCAL
*pfn_WSAStartup
) (WORD wVersionRequired
, LPWSADATA lpWSAData
);
3169 void (PASCAL
*pfn_WSASetLastError
) (int iError
);
3170 int (PASCAL
*pfn_WSAGetLastError
) (void);
3171 int (PASCAL
*pfn_WSAEventSelect
) (SOCKET s
, HANDLE hEventObject
, long lNetworkEvents
);
3172 HANDLE (PASCAL
*pfn_WSACreateEvent
) (void);
3173 int (PASCAL
*pfn_WSACloseEvent
) (HANDLE hEvent
);
3174 int (PASCAL
*pfn_socket
) (int af
, int type
, int protocol
);
3175 int (PASCAL
*pfn_bind
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
3176 int (PASCAL
*pfn_connect
) (SOCKET s
, const struct sockaddr
*addr
, int namelen
);
3177 int (PASCAL
*pfn_ioctlsocket
) (SOCKET s
, long cmd
, u_long
*argp
);
3178 int (PASCAL
*pfn_recv
) (SOCKET s
, char * buf
, int len
, int flags
);
3179 int (PASCAL
*pfn_send
) (SOCKET s
, const char * buf
, int len
, int flags
);
3180 int (PASCAL
*pfn_closesocket
) (SOCKET s
);
3181 int (PASCAL
*pfn_shutdown
) (SOCKET s
, int how
);
3182 int (PASCAL
*pfn_WSACleanup
) (void);
3184 u_short (PASCAL
*pfn_htons
) (u_short hostshort
);
3185 u_short (PASCAL
*pfn_ntohs
) (u_short netshort
);
3186 unsigned long (PASCAL
*pfn_inet_addr
) (const char * cp
);
3187 int (PASCAL
*pfn_gethostname
) (char * name
, int namelen
);
3188 struct hostent
* (PASCAL
*pfn_gethostbyname
) (const char * name
);
3189 struct servent
* (PASCAL
*pfn_getservbyname
) (const char * name
, const char * proto
);
3190 int (PASCAL
*pfn_getpeername
) (SOCKET s
, struct sockaddr
*addr
, int * namelen
);
3191 int (PASCAL
*pfn_setsockopt
) (SOCKET s
, int level
, int optname
,
3192 const char * optval
, int optlen
);
3193 int (PASCAL
*pfn_listen
) (SOCKET s
, int backlog
);
3194 int (PASCAL
*pfn_getsockname
) (SOCKET s
, struct sockaddr
* name
,
3196 SOCKET (PASCAL
*pfn_accept
) (SOCKET s
, struct sockaddr
* addr
, int * addrlen
);
3197 int (PASCAL
*pfn_recvfrom
) (SOCKET s
, char * buf
, int len
, int flags
,
3198 struct sockaddr
* from
, int * fromlen
);
3199 int (PASCAL
*pfn_sendto
) (SOCKET s
, const char * buf
, int len
, int flags
,
3200 const struct sockaddr
* to
, int tolen
);
3202 /* SetHandleInformation is only needed to make sockets non-inheritable. */
3203 BOOL (WINAPI
*pfn_SetHandleInformation
) (HANDLE object
, DWORD mask
, DWORD flags
);
3204 #ifndef HANDLE_FLAG_INHERIT
3205 #define HANDLE_FLAG_INHERIT 1
3209 static int winsock_inuse
;
3214 if (winsock_lib
!= NULL
&& winsock_inuse
== 0)
3216 /* Not sure what would cause WSAENETDOWN, or even if it can happen
3217 after WSAStartup returns successfully, but it seems reasonable
3218 to allow unloading winsock anyway in that case. */
3219 if (pfn_WSACleanup () == 0 ||
3220 pfn_WSAGetLastError () == WSAENETDOWN
)
3222 if (FreeLibrary (winsock_lib
))
3231 init_winsock (int load_now
)
3233 WSADATA winsockData
;
3235 if (winsock_lib
!= NULL
)
3238 pfn_SetHandleInformation
= NULL
;
3239 pfn_SetHandleInformation
3240 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
3241 "SetHandleInformation");
3243 winsock_lib
= LoadLibrary ("Ws2_32.dll");
3245 if (winsock_lib
!= NULL
)
3247 /* dynamically link to socket functions */
3249 #define LOAD_PROC(fn) \
3250 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
3253 LOAD_PROC( WSAStartup
);
3254 LOAD_PROC( WSASetLastError
);
3255 LOAD_PROC( WSAGetLastError
);
3256 LOAD_PROC( WSAEventSelect
);
3257 LOAD_PROC( WSACreateEvent
);
3258 LOAD_PROC( WSACloseEvent
);
3259 LOAD_PROC( socket
);
3261 LOAD_PROC( connect
);
3262 LOAD_PROC( ioctlsocket
);
3265 LOAD_PROC( closesocket
);
3266 LOAD_PROC( shutdown
);
3269 LOAD_PROC( inet_addr
);
3270 LOAD_PROC( gethostname
);
3271 LOAD_PROC( gethostbyname
);
3272 LOAD_PROC( getservbyname
);
3273 LOAD_PROC( getpeername
);
3274 LOAD_PROC( WSACleanup
);
3275 LOAD_PROC( setsockopt
);
3276 LOAD_PROC( listen
);
3277 LOAD_PROC( getsockname
);
3278 LOAD_PROC( accept
);
3279 LOAD_PROC( recvfrom
);
3280 LOAD_PROC( sendto
);
3283 /* specify version 1.1 of winsock */
3284 if (pfn_WSAStartup (0x101, &winsockData
) == 0)
3286 if (winsockData
.wVersion
!= 0x101)
3291 /* Report that winsock exists and is usable, but leave
3292 socket functions disabled. I am assuming that calling
3293 WSAStartup does not require any network interaction,
3294 and in particular does not cause or require a dial-up
3295 connection to be established. */
3298 FreeLibrary (winsock_lib
);
3306 FreeLibrary (winsock_lib
);
3316 /* function to set h_errno for compatability; map winsock error codes to
3317 normal system codes where they overlap (non-overlapping definitions
3318 are already in <sys/socket.h> */
3322 if (winsock_lib
== NULL
)
3325 h_errno
= pfn_WSAGetLastError ();
3329 case WSAEACCES
: h_errno
= EACCES
; break;
3330 case WSAEBADF
: h_errno
= EBADF
; break;
3331 case WSAEFAULT
: h_errno
= EFAULT
; break;
3332 case WSAEINTR
: h_errno
= EINTR
; break;
3333 case WSAEINVAL
: h_errno
= EINVAL
; break;
3334 case WSAEMFILE
: h_errno
= EMFILE
; break;
3335 case WSAENAMETOOLONG
: h_errno
= ENAMETOOLONG
; break;
3336 case WSAENOTEMPTY
: h_errno
= ENOTEMPTY
; break;
3344 if (h_errno
== 0 && winsock_lib
!= NULL
)
3345 pfn_WSASetLastError (0);
3348 /* Extend strerror to handle the winsock-specific error codes. */
3352 } _wsa_errlist
[] = {
3353 WSAEINTR
, "Interrupted function call",
3354 WSAEBADF
, "Bad file descriptor",
3355 WSAEACCES
, "Permission denied",
3356 WSAEFAULT
, "Bad address",
3357 WSAEINVAL
, "Invalid argument",
3358 WSAEMFILE
, "Too many open files",
3360 WSAEWOULDBLOCK
, "Resource temporarily unavailable",
3361 WSAEINPROGRESS
, "Operation now in progress",
3362 WSAEALREADY
, "Operation already in progress",
3363 WSAENOTSOCK
, "Socket operation on non-socket",
3364 WSAEDESTADDRREQ
, "Destination address required",
3365 WSAEMSGSIZE
, "Message too long",
3366 WSAEPROTOTYPE
, "Protocol wrong type for socket",
3367 WSAENOPROTOOPT
, "Bad protocol option",
3368 WSAEPROTONOSUPPORT
, "Protocol not supported",
3369 WSAESOCKTNOSUPPORT
, "Socket type not supported",
3370 WSAEOPNOTSUPP
, "Operation not supported",
3371 WSAEPFNOSUPPORT
, "Protocol family not supported",
3372 WSAEAFNOSUPPORT
, "Address family not supported by protocol family",
3373 WSAEADDRINUSE
, "Address already in use",
3374 WSAEADDRNOTAVAIL
, "Cannot assign requested address",
3375 WSAENETDOWN
, "Network is down",
3376 WSAENETUNREACH
, "Network is unreachable",
3377 WSAENETRESET
, "Network dropped connection on reset",
3378 WSAECONNABORTED
, "Software caused connection abort",
3379 WSAECONNRESET
, "Connection reset by peer",
3380 WSAENOBUFS
, "No buffer space available",
3381 WSAEISCONN
, "Socket is already connected",
3382 WSAENOTCONN
, "Socket is not connected",
3383 WSAESHUTDOWN
, "Cannot send after socket shutdown",
3384 WSAETOOMANYREFS
, "Too many references", /* not sure */
3385 WSAETIMEDOUT
, "Connection timed out",
3386 WSAECONNREFUSED
, "Connection refused",
3387 WSAELOOP
, "Network loop", /* not sure */
3388 WSAENAMETOOLONG
, "Name is too long",
3389 WSAEHOSTDOWN
, "Host is down",
3390 WSAEHOSTUNREACH
, "No route to host",
3391 WSAENOTEMPTY
, "Buffer not empty", /* not sure */
3392 WSAEPROCLIM
, "Too many processes",
3393 WSAEUSERS
, "Too many users", /* not sure */
3394 WSAEDQUOT
, "Double quote in host name", /* really not sure */
3395 WSAESTALE
, "Data is stale", /* not sure */
3396 WSAEREMOTE
, "Remote error", /* not sure */
3398 WSASYSNOTREADY
, "Network subsystem is unavailable",
3399 WSAVERNOTSUPPORTED
, "WINSOCK.DLL version out of range",
3400 WSANOTINITIALISED
, "Winsock not initialized successfully",
3401 WSAEDISCON
, "Graceful shutdown in progress",
3403 WSAENOMORE
, "No more operations allowed", /* not sure */
3404 WSAECANCELLED
, "Operation cancelled", /* not sure */
3405 WSAEINVALIDPROCTABLE
, "Invalid procedure table from service provider",
3406 WSAEINVALIDPROVIDER
, "Invalid service provider version number",
3407 WSAEPROVIDERFAILEDINIT
, "Unable to initialize a service provider",
3408 WSASYSCALLFAILURE
, "System call failure",
3409 WSASERVICE_NOT_FOUND
, "Service not found", /* not sure */
3410 WSATYPE_NOT_FOUND
, "Class type not found",
3411 WSA_E_NO_MORE
, "No more resources available", /* really not sure */
3412 WSA_E_CANCELLED
, "Operation already cancelled", /* really not sure */
3413 WSAEREFUSED
, "Operation refused", /* not sure */
3416 WSAHOST_NOT_FOUND
, "Host not found",
3417 WSATRY_AGAIN
, "Authoritative host not found during name lookup",
3418 WSANO_RECOVERY
, "Non-recoverable error during name lookup",
3419 WSANO_DATA
, "Valid name, no data record of requested type",
3425 sys_strerror(int error_no
)
3428 static char unknown_msg
[40];
3430 if (error_no
>= 0 && error_no
< sys_nerr
)
3431 return sys_errlist
[error_no
];
3433 for (i
= 0; _wsa_errlist
[i
].errnum
>= 0; i
++)
3434 if (_wsa_errlist
[i
].errnum
== error_no
)
3435 return _wsa_errlist
[i
].msg
;
3437 sprintf(unknown_msg
, "Unidentified error: %d", error_no
);
3441 /* [andrewi 3-May-96] I've had conflicting results using both methods,
3442 but I believe the method of keeping the socket handle separate (and
3443 insuring it is not inheritable) is the correct one. */
3445 //#define SOCK_REPLACE_HANDLE
3447 #ifdef SOCK_REPLACE_HANDLE
3448 #define SOCK_HANDLE(fd) ((SOCKET) _get_osfhandle (fd))
3450 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
3453 int socket_to_fd (SOCKET s
);
3456 sys_socket(int af
, int type
, int protocol
)
3460 if (winsock_lib
== NULL
)
3463 return INVALID_SOCKET
;
3468 /* call the real socket function */
3469 s
= pfn_socket (af
, type
, protocol
);
3471 if (s
!= INVALID_SOCKET
)
3472 return socket_to_fd (s
);
3478 /* Convert a SOCKET to a file descriptor. */
3480 socket_to_fd (SOCKET s
)
3485 /* Although under NT 3.5 _open_osfhandle will accept a socket
3486 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
3487 that does not work under NT 3.1. However, we can get the same
3488 effect by using a backdoor function to replace an existing
3489 descriptor handle with the one we want. */
3491 /* allocate a file descriptor (with appropriate flags) */
3492 fd
= _open ("NUL:", _O_RDWR
);
3495 #ifdef SOCK_REPLACE_HANDLE
3496 /* now replace handle to NUL with our socket handle */
3497 CloseHandle ((HANDLE
) _get_osfhandle (fd
));
3499 _set_osfhnd (fd
, s
);
3500 /* setmode (fd, _O_BINARY); */
3502 /* Make a non-inheritable copy of the socket handle. Note
3503 that it is possible that sockets aren't actually kernel
3504 handles, which appears to be the case on Windows 9x when
3505 the MS Proxy winsock client is installed. */
3507 /* Apparently there is a bug in NT 3.51 with some service
3508 packs, which prevents using DuplicateHandle to make a
3509 socket handle non-inheritable (causes WSACleanup to
3510 hang). The work-around is to use SetHandleInformation
3511 instead if it is available and implemented. */
3512 if (pfn_SetHandleInformation
)
3514 pfn_SetHandleInformation ((HANDLE
) s
, HANDLE_FLAG_INHERIT
, 0);
3518 HANDLE parent
= GetCurrentProcess ();
3519 HANDLE new_s
= INVALID_HANDLE_VALUE
;
3521 if (DuplicateHandle (parent
,
3527 DUPLICATE_SAME_ACCESS
))
3529 /* It is possible that DuplicateHandle succeeds even
3530 though the socket wasn't really a kernel handle,
3531 because a real handle has the same value. So
3532 test whether the new handle really is a socket. */
3533 long nonblocking
= 0;
3534 if (pfn_ioctlsocket ((SOCKET
) new_s
, FIONBIO
, &nonblocking
) == 0)
3536 pfn_closesocket (s
);
3541 CloseHandle (new_s
);
3546 fd_info
[fd
].hnd
= (HANDLE
) s
;
3549 /* set our own internal flags */
3550 fd_info
[fd
].flags
= FILE_SOCKET
| FILE_BINARY
| FILE_READ
| FILE_WRITE
;
3556 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
3558 /* attach child_process to fd_info */
3559 if (fd_info
[ fd
].cp
!= NULL
)
3561 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd
));
3565 fd_info
[ fd
].cp
= cp
;
3568 winsock_inuse
++; /* count open sockets */
3575 pfn_closesocket (s
);
3582 sys_bind (int s
, const struct sockaddr
* addr
, int namelen
)
3584 if (winsock_lib
== NULL
)
3587 return SOCKET_ERROR
;
3591 if (fd_info
[s
].flags
& FILE_SOCKET
)
3593 int rc
= pfn_bind (SOCK_HANDLE (s
), addr
, namelen
);
3594 if (rc
== SOCKET_ERROR
)
3599 return SOCKET_ERROR
;
3604 sys_connect (int s
, const struct sockaddr
* name
, int namelen
)
3606 if (winsock_lib
== NULL
)
3609 return SOCKET_ERROR
;
3613 if (fd_info
[s
].flags
& FILE_SOCKET
)
3615 int rc
= pfn_connect (SOCK_HANDLE (s
), name
, namelen
);
3616 if (rc
== SOCKET_ERROR
)
3621 return SOCKET_ERROR
;
3625 sys_htons (u_short hostshort
)
3627 return (winsock_lib
!= NULL
) ?
3628 pfn_htons (hostshort
) : hostshort
;
3632 sys_ntohs (u_short netshort
)
3634 return (winsock_lib
!= NULL
) ?
3635 pfn_ntohs (netshort
) : netshort
;
3639 sys_inet_addr (const char * cp
)
3641 return (winsock_lib
!= NULL
) ?
3642 pfn_inet_addr (cp
) : INADDR_NONE
;
3646 sys_gethostname (char * name
, int namelen
)
3648 if (winsock_lib
!= NULL
)
3649 return pfn_gethostname (name
, namelen
);
3651 if (namelen
> MAX_COMPUTERNAME_LENGTH
)
3652 return !GetComputerName (name
, (DWORD
*)&namelen
);
3655 return SOCKET_ERROR
;
3659 sys_gethostbyname(const char * name
)
3661 struct hostent
* host
;
3663 if (winsock_lib
== NULL
)
3670 host
= pfn_gethostbyname (name
);
3677 sys_getservbyname(const char * name
, const char * proto
)
3679 struct servent
* serv
;
3681 if (winsock_lib
== NULL
)
3688 serv
= pfn_getservbyname (name
, proto
);
3695 sys_getpeername (int s
, struct sockaddr
*addr
, int * namelen
)
3697 if (winsock_lib
== NULL
)
3700 return SOCKET_ERROR
;
3704 if (fd_info
[s
].flags
& FILE_SOCKET
)
3706 int rc
= pfn_getpeername (SOCK_HANDLE (s
), addr
, namelen
);
3707 if (rc
== SOCKET_ERROR
)
3712 return SOCKET_ERROR
;
3717 sys_shutdown (int s
, int how
)
3719 if (winsock_lib
== NULL
)
3722 return SOCKET_ERROR
;
3726 if (fd_info
[s
].flags
& FILE_SOCKET
)
3728 int rc
= pfn_shutdown (SOCK_HANDLE (s
), how
);
3729 if (rc
== SOCKET_ERROR
)
3734 return SOCKET_ERROR
;
3738 sys_setsockopt (int s
, int level
, int optname
, const void * optval
, int optlen
)
3740 if (winsock_lib
== NULL
)
3743 return SOCKET_ERROR
;
3747 if (fd_info
[s
].flags
& FILE_SOCKET
)
3749 int rc
= pfn_setsockopt (SOCK_HANDLE (s
), level
, optname
,
3750 (const char *)optval
, optlen
);
3751 if (rc
== SOCKET_ERROR
)
3756 return SOCKET_ERROR
;
3760 sys_listen (int s
, int backlog
)
3762 if (winsock_lib
== NULL
)
3765 return SOCKET_ERROR
;
3769 if (fd_info
[s
].flags
& FILE_SOCKET
)
3771 int rc
= pfn_listen (SOCK_HANDLE (s
), backlog
);
3772 if (rc
== SOCKET_ERROR
)
3775 fd_info
[s
].flags
|= FILE_LISTEN
;
3779 return SOCKET_ERROR
;
3783 sys_getsockname (int s
, struct sockaddr
* name
, int * namelen
)
3785 if (winsock_lib
== NULL
)
3788 return SOCKET_ERROR
;
3792 if (fd_info
[s
].flags
& FILE_SOCKET
)
3794 int rc
= pfn_getsockname (SOCK_HANDLE (s
), name
, namelen
);
3795 if (rc
== SOCKET_ERROR
)
3800 return SOCKET_ERROR
;
3804 sys_accept (int s
, struct sockaddr
* addr
, int * addrlen
)
3806 if (winsock_lib
== NULL
)
3813 if (fd_info
[s
].flags
& FILE_LISTEN
)
3815 SOCKET t
= pfn_accept (SOCK_HANDLE (s
), addr
, addrlen
);
3817 if (t
== INVALID_SOCKET
)
3820 fd
= socket_to_fd (t
);
3822 fd_info
[s
].cp
->status
= STATUS_READ_ACKNOWLEDGED
;
3823 ResetEvent (fd_info
[s
].cp
->char_avail
);
3831 sys_recvfrom (int s
, char * buf
, int len
, int flags
,
3832 struct sockaddr
* from
, int * fromlen
)
3834 if (winsock_lib
== NULL
)
3837 return SOCKET_ERROR
;
3841 if (fd_info
[s
].flags
& FILE_SOCKET
)
3843 int rc
= pfn_recvfrom (SOCK_HANDLE (s
), buf
, len
, flags
, from
, fromlen
);
3844 if (rc
== SOCKET_ERROR
)
3849 return SOCKET_ERROR
;
3853 sys_sendto (int s
, const char * buf
, int len
, int flags
,
3854 const struct sockaddr
* to
, int tolen
)
3856 if (winsock_lib
== NULL
)
3859 return SOCKET_ERROR
;
3863 if (fd_info
[s
].flags
& FILE_SOCKET
)
3865 int rc
= pfn_sendto (SOCK_HANDLE (s
), buf
, len
, flags
, to
, tolen
);
3866 if (rc
== SOCKET_ERROR
)
3871 return SOCKET_ERROR
;
3874 /* Windows does not have an fcntl function. Provide an implementation
3875 solely for making sockets non-blocking. */
3877 fcntl (int s
, int cmd
, int options
)
3879 if (winsock_lib
== NULL
)
3886 if (fd_info
[s
].flags
& FILE_SOCKET
)
3888 if (cmd
== F_SETFL
&& options
== O_NDELAY
)
3890 unsigned long nblock
= 1;
3891 int rc
= pfn_ioctlsocket (SOCK_HANDLE (s
), FIONBIO
, &nblock
);
3892 if (rc
== SOCKET_ERROR
)
3894 /* Keep track of the fact that we set this to non-blocking. */
3895 fd_info
[s
].flags
|= FILE_NDELAY
;
3901 return SOCKET_ERROR
;
3905 return SOCKET_ERROR
;
3908 #endif /* HAVE_SOCKETS */
3911 /* Shadow main io functions: we need to handle pipes and sockets more
3912 intelligently, and implement non-blocking mode as well. */
3925 if (fd
< MAXDESC
&& fd_info
[fd
].cp
)
3927 child_process
* cp
= fd_info
[fd
].cp
;
3929 fd_info
[fd
].cp
= NULL
;
3931 if (CHILD_ACTIVE (cp
))
3933 /* if last descriptor to active child_process then cleanup */
3935 for (i
= 0; i
< MAXDESC
; i
++)
3939 if (fd_info
[i
].cp
== cp
)
3945 if (fd_info
[fd
].flags
& FILE_SOCKET
)
3947 #ifndef SOCK_REPLACE_HANDLE
3948 if (winsock_lib
== NULL
) abort ();
3950 pfn_shutdown (SOCK_HANDLE (fd
), 2);
3951 rc
= pfn_closesocket (SOCK_HANDLE (fd
));
3953 winsock_inuse
--; /* count open sockets */
3961 /* Note that sockets do not need special treatment here (at least on
3962 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
3963 closesocket is equivalent to CloseHandle, which is to be expected
3964 because socket handles are fully fledged kernel handles. */
3967 if (rc
== 0 && fd
< MAXDESC
)
3968 fd_info
[fd
].flags
= 0;
3979 if (new_fd
>= 0 && new_fd
< MAXDESC
)
3981 /* duplicate our internal info as well */
3982 fd_info
[new_fd
] = fd_info
[fd
];
3989 sys_dup2 (int src
, int dst
)
3993 if (dst
< 0 || dst
>= MAXDESC
)
3999 /* make sure we close the destination first if it's a pipe or socket */
4000 if (src
!= dst
&& fd_info
[dst
].flags
!= 0)
4003 rc
= _dup2 (src
, dst
);
4006 /* duplicate our internal info as well */
4007 fd_info
[dst
] = fd_info
[src
];
4012 /* Unix pipe() has only one arg */
4014 sys_pipe (int * phandles
)
4019 /* make pipe handles non-inheritable; when we spawn a child, we
4020 replace the relevant handle with an inheritable one. Also put
4021 pipes into binary mode; we will do text mode translation ourselves
4023 rc
= _pipe (phandles
, 0, _O_NOINHERIT
| _O_BINARY
);
4027 /* Protect against overflow, since Windows can open more handles than
4028 our fd_info array has room for. */
4029 if (phandles
[0] >= MAXDESC
|| phandles
[1] >= MAXDESC
)
4031 _close (phandles
[0]);
4032 _close (phandles
[1]);
4037 flags
= FILE_PIPE
| FILE_READ
| FILE_BINARY
;
4038 fd_info
[phandles
[0]].flags
= flags
;
4040 flags
= FILE_PIPE
| FILE_WRITE
| FILE_BINARY
;
4041 fd_info
[phandles
[1]].flags
= flags
;
4049 extern int w32_pipe_read_delay
;
4051 /* Function to do blocking read of one byte, needed to implement
4052 select. It is only allowed on sockets and pipes. */
4054 _sys_read_ahead (int fd
)
4059 if (fd
< 0 || fd
>= MAXDESC
)
4060 return STATUS_READ_ERROR
;
4062 cp
= fd_info
[fd
].cp
;
4064 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
4065 return STATUS_READ_ERROR
;
4067 if ((fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
)) == 0
4068 || (fd_info
[fd
].flags
& FILE_READ
) == 0)
4070 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe or socket!\n", fd
));
4074 cp
->status
= STATUS_READ_IN_PROGRESS
;
4076 if (fd_info
[fd
].flags
& FILE_PIPE
)
4078 rc
= _read (fd
, &cp
->chr
, sizeof (char));
4080 /* Give subprocess time to buffer some more output for us before
4081 reporting that input is available; we need this because Windows 95
4082 connects DOS programs to pipes by making the pipe appear to be
4083 the normal console stdout - as a result most DOS programs will
4084 write to stdout without buffering, ie. one character at a
4085 time. Even some W32 programs do this - "dir" in a command
4086 shell on NT is very slow if we don't do this. */
4089 int wait
= w32_pipe_read_delay
;
4095 /* Yield remainder of our time slice, effectively giving a
4096 temporary priority boost to the child process. */
4101 else if (fd_info
[fd
].flags
& FILE_SOCKET
)
4103 unsigned long nblock
= 0;
4104 /* We always want this to block, so temporarily disable NDELAY. */
4105 if (fd_info
[fd
].flags
& FILE_NDELAY
)
4106 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
4108 rc
= pfn_recv (SOCK_HANDLE (fd
), &cp
->chr
, sizeof (char), 0);
4110 if (fd_info
[fd
].flags
& FILE_NDELAY
)
4113 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
4118 if (rc
== sizeof (char))
4119 cp
->status
= STATUS_READ_SUCCEEDED
;
4121 cp
->status
= STATUS_READ_FAILED
;
4127 _sys_wait_accept (int fd
)
4133 if (fd
< 0 || fd
>= MAXDESC
)
4134 return STATUS_READ_ERROR
;
4136 cp
= fd_info
[fd
].cp
;
4138 if (cp
== NULL
|| cp
->fd
!= fd
|| cp
->status
!= STATUS_READ_READY
)
4139 return STATUS_READ_ERROR
;
4141 cp
->status
= STATUS_READ_FAILED
;
4143 hEv
= pfn_WSACreateEvent ();
4144 rc
= pfn_WSAEventSelect (SOCK_HANDLE (fd
), hEv
, FD_ACCEPT
);
4145 if (rc
!= SOCKET_ERROR
)
4147 rc
= WaitForSingleObject (hEv
, INFINITE
);
4148 pfn_WSAEventSelect (SOCK_HANDLE (fd
), NULL
, 0);
4149 if (rc
== WAIT_OBJECT_0
)
4150 cp
->status
= STATUS_READ_SUCCEEDED
;
4152 pfn_WSACloseEvent (hEv
);
4158 sys_read (int fd
, char * buffer
, unsigned int count
)
4163 char * orig_buffer
= buffer
;
4171 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
))
4173 child_process
*cp
= fd_info
[fd
].cp
;
4175 if ((fd_info
[fd
].flags
& FILE_READ
) == 0)
4183 /* re-read CR carried over from last read */
4184 if (fd_info
[fd
].flags
& FILE_LAST_CR
)
4186 if (fd_info
[fd
].flags
& FILE_BINARY
) abort ();
4190 fd_info
[fd
].flags
&= ~FILE_LAST_CR
;
4193 /* presence of a child_process structure means we are operating in
4194 non-blocking mode - otherwise we just call _read directly.
4195 Note that the child_process structure might be missing because
4196 reap_subprocess has been called; in this case the pipe is
4197 already broken, so calling _read on it is okay. */
4200 int current_status
= cp
->status
;
4202 switch (current_status
)
4204 case STATUS_READ_FAILED
:
4205 case STATUS_READ_ERROR
:
4206 /* report normal EOF if nothing in buffer */
4208 fd_info
[fd
].flags
|= FILE_AT_EOF
;
4211 case STATUS_READ_READY
:
4212 case STATUS_READ_IN_PROGRESS
:
4213 DebPrint (("sys_read called when read is in progress\n"));
4214 errno
= EWOULDBLOCK
;
4217 case STATUS_READ_SUCCEEDED
:
4218 /* consume read-ahead char */
4219 *buffer
++ = cp
->chr
;
4222 cp
->status
= STATUS_READ_ACKNOWLEDGED
;
4223 ResetEvent (cp
->char_avail
);
4225 case STATUS_READ_ACKNOWLEDGED
:
4229 DebPrint (("sys_read: bad status %d\n", current_status
));
4234 if (fd_info
[fd
].flags
& FILE_PIPE
)
4236 PeekNamedPipe ((HANDLE
) _get_osfhandle (fd
), NULL
, 0, NULL
, &waiting
, NULL
);
4237 to_read
= min (waiting
, (DWORD
) count
);
4240 nchars
+= _read (fd
, buffer
, to_read
);
4243 else /* FILE_SOCKET */
4245 if (winsock_lib
== NULL
) abort ();
4247 /* do the equivalent of a non-blocking read */
4248 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONREAD
, &waiting
);
4249 if (waiting
== 0 && nchars
== 0)
4251 h_errno
= errno
= EWOULDBLOCK
;
4257 /* always use binary mode for sockets */
4258 int res
= pfn_recv (SOCK_HANDLE (fd
), buffer
, count
, 0);
4259 if (res
== SOCKET_ERROR
)
4261 DebPrint(("sys_read.recv failed with error %d on socket %ld\n",
4262 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
4273 int nread
= _read (fd
, buffer
, count
);
4276 else if (nchars
== 0)
4281 fd_info
[fd
].flags
|= FILE_AT_EOF
;
4282 /* Perform text mode translation if required. */
4283 else if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
4285 nchars
= crlf_to_lf (nchars
, orig_buffer
);
4286 /* If buffer contains only CR, return that. To be absolutely
4287 sure we should attempt to read the next char, but in
4288 practice a CR to be followed by LF would not appear by
4289 itself in the buffer. */
4290 if (nchars
> 1 && orig_buffer
[nchars
- 1] == 0x0d)
4292 fd_info
[fd
].flags
|= FILE_LAST_CR
;
4298 nchars
= _read (fd
, buffer
, count
);
4303 /* For now, don't bother with a non-blocking mode */
4305 sys_write (int fd
, const void * buffer
, unsigned int count
)
4315 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& (FILE_PIPE
| FILE_SOCKET
))
4317 if ((fd_info
[fd
].flags
& FILE_WRITE
) == 0)
4323 /* Perform text mode translation if required. */
4324 if ((fd_info
[fd
].flags
& FILE_BINARY
) == 0)
4326 char * tmpbuf
= alloca (count
* 2);
4327 unsigned char * src
= (void *)buffer
;
4328 unsigned char * dst
= tmpbuf
;
4333 unsigned char *next
;
4334 /* copy next line or remaining bytes */
4335 next
= _memccpy (dst
, src
, '\n', nbytes
);
4338 /* copied one line ending with '\n' */
4339 int copied
= next
- dst
;
4342 /* insert '\r' before '\n' */
4349 /* copied remaining partial line -> now finished */
4357 if (fd
< MAXDESC
&& fd_info
[fd
].flags
& FILE_SOCKET
)
4359 unsigned long nblock
= 0;
4360 if (winsock_lib
== NULL
) abort ();
4362 /* TODO: implement select() properly so non-blocking I/O works. */
4363 /* For now, make sure the write blocks. */
4364 if (fd_info
[fd
].flags
& FILE_NDELAY
)
4365 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
4367 nchars
= pfn_send (SOCK_HANDLE (fd
), buffer
, count
, 0);
4369 /* Set the socket back to non-blocking if it was before,
4370 for other operations that support it. */
4371 if (fd_info
[fd
].flags
& FILE_NDELAY
)
4374 pfn_ioctlsocket (SOCK_HANDLE (fd
), FIONBIO
, &nblock
);
4377 if (nchars
== SOCKET_ERROR
)
4379 DebPrint(("sys_write.send failed with error %d on socket %ld\n",
4380 pfn_WSAGetLastError (), SOCK_HANDLE (fd
)));
4386 nchars
= _write (fd
, buffer
, count
);
4392 check_windows_init_file ()
4394 extern int noninteractive
, inhibit_window_system
;
4396 /* A common indication that Emacs is not installed properly is when
4397 it cannot find the Windows installation file. If this file does
4398 not exist in the expected place, tell the user. */
4400 if (!noninteractive
&& !inhibit_window_system
)
4402 extern Lisp_Object Vwindow_system
, Vload_path
, Qfile_exists_p
;
4403 Lisp_Object objs
[2];
4404 Lisp_Object full_load_path
;
4405 Lisp_Object init_file
;
4408 objs
[0] = Vload_path
;
4409 objs
[1] = decode_env_path (0, (getenv ("EMACSLOADPATH")));
4410 full_load_path
= Fappend (2, objs
);
4411 init_file
= build_string ("term/w32-win");
4412 fd
= openp (full_load_path
, init_file
, Fget_load_suffixes (), NULL
, Qnil
);
4415 Lisp_Object load_path_print
= Fprin1_to_string (full_load_path
, Qnil
);
4416 char *init_file_name
= SDATA (init_file
);
4417 char *load_path
= SDATA (load_path_print
);
4418 char *buffer
= alloca (1024
4419 + strlen (init_file_name
)
4420 + strlen (load_path
));
4423 "The Emacs Windows initialization file \"%s.el\" "
4424 "could not be found in your Emacs installation. "
4425 "Emacs checked the following directories for this file:\n"
4427 "When Emacs cannot find this file, it usually means that it "
4428 "was not installed properly, or its distribution file was "
4429 "not unpacked properly.\nSee the README.W32 file in the "
4430 "top-level Emacs directory for more information.",
4431 init_file_name
, load_path
);
4434 "Emacs Abort Dialog",
4435 MB_OK
| MB_ICONEXCLAMATION
| MB_TASKMODAL
);
4436 /* Use the low-level Emacs abort. */
4451 /* shutdown the socket interface if necessary */
4462 /* Initialise the socket interface now if available and requested by
4463 the user by defining PRELOAD_WINSOCK; otherwise loading will be
4464 delayed until open-network-stream is called (w32-has-winsock can
4465 also be used to dynamically load or reload winsock).
4467 Conveniently, init_environment is called before us, so
4468 PRELOAD_WINSOCK can be set in the registry. */
4470 /* Always initialize this correctly. */
4473 if (getenv ("PRELOAD_WINSOCK") != NULL
)
4474 init_winsock (TRUE
);
4477 /* Initial preparation for subprocess support: replace our standard
4478 handles with non-inheritable versions. */
4481 HANDLE stdin_save
= INVALID_HANDLE_VALUE
;
4482 HANDLE stdout_save
= INVALID_HANDLE_VALUE
;
4483 HANDLE stderr_save
= INVALID_HANDLE_VALUE
;
4485 parent
= GetCurrentProcess ();
4487 /* ignore errors when duplicating and closing; typically the
4488 handles will be invalid when running as a gui program. */
4489 DuplicateHandle (parent
,
4490 GetStdHandle (STD_INPUT_HANDLE
),
4495 DUPLICATE_SAME_ACCESS
);
4497 DuplicateHandle (parent
,
4498 GetStdHandle (STD_OUTPUT_HANDLE
),
4503 DUPLICATE_SAME_ACCESS
);
4505 DuplicateHandle (parent
,
4506 GetStdHandle (STD_ERROR_HANDLE
),
4511 DUPLICATE_SAME_ACCESS
);
4517 if (stdin_save
!= INVALID_HANDLE_VALUE
)
4518 _open_osfhandle ((long) stdin_save
, O_TEXT
);
4520 _open ("nul", O_TEXT
| O_NOINHERIT
| O_RDONLY
);
4523 if (stdout_save
!= INVALID_HANDLE_VALUE
)
4524 _open_osfhandle ((long) stdout_save
, O_TEXT
);
4526 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
4529 if (stderr_save
!= INVALID_HANDLE_VALUE
)
4530 _open_osfhandle ((long) stderr_save
, O_TEXT
);
4532 _open ("nul", O_TEXT
| O_NOINHERIT
| O_WRONLY
);
4536 /* unfortunately, atexit depends on implementation of malloc */
4537 /* atexit (term_ntproc); */
4538 signal (SIGABRT
, term_ntproc
);
4540 /* determine which drives are fixed, for GetCachedVolumeInformation */
4542 /* GetDriveType must have trailing backslash. */
4543 char drive
[] = "A:\\";
4545 /* Loop over all possible drive letters */
4546 while (*drive
<= 'Z')
4548 /* Record if this drive letter refers to a fixed drive. */
4549 fixed_drives
[DRIVE_INDEX (*drive
)] =
4550 (GetDriveType (drive
) == DRIVE_FIXED
);
4555 /* Reset the volume info cache. */
4556 volume_cache
= NULL
;
4559 /* Check to see if Emacs has been installed correctly. */
4560 check_windows_init_file ();
4564 shutdown_handler ensures that buffers' autosave files are
4565 up to date when the user logs off, or the system shuts down.
4567 BOOL WINAPI
shutdown_handler(DWORD type
)
4569 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
4570 if (type
== CTRL_CLOSE_EVENT
/* User closes console window. */
4571 || type
== CTRL_LOGOFF_EVENT
/* User logs off. */
4572 || type
== CTRL_SHUTDOWN_EVENT
) /* User shutsdown. */
4574 /* Shut down cleanly, making sure autosave files are up to date. */
4575 shut_down_emacs (0, 0, Qnil
);
4578 /* Allow other handlers to handle this signal. */
4583 globals_of_w32 is used to initialize those global variables that
4584 must always be initialized on startup even when the global variable
4585 initialized is non zero (see the function main in emacs.c).
4590 HMODULE kernel32
= GetModuleHandle ("kernel32.dll");
4592 get_process_times_fn
= (GetProcessTimes_Proc
)
4593 GetProcAddress (kernel32
, "GetProcessTimes");
4595 g_b_init_is_windows_9x
= 0;
4596 g_b_init_open_process_token
= 0;
4597 g_b_init_get_token_information
= 0;
4598 g_b_init_lookup_account_sid
= 0;
4599 g_b_init_get_sid_identifier_authority
= 0;
4600 g_b_init_get_sid_sub_authority
= 0;
4601 g_b_init_get_sid_sub_authority_count
= 0;
4602 g_b_init_get_file_security
= 0;
4603 g_b_init_get_security_descriptor_owner
= 0;
4604 g_b_init_get_security_descriptor_group
= 0;
4605 g_b_init_is_valid_sid
= 0;
4606 /* The following sets a handler for shutdown notifications for
4607 console apps. This actually applies to Emacs in both console and
4608 GUI modes, since we had to fool windows into thinking emacs is a
4609 console application to get console mode to work. */
4610 SetConsoleCtrlHandler(shutdown_handler
, TRUE
);
4612 /* "None" is the default group name on standalone workstations. */
4613 strcpy (dflt_group_name
, "None");
4618 /* arch-tag: 90442dd3-37be-482b-b272-ac752e3049f1
4619 (do not change this comment) */