Daniel Engeler <engeler at gmail.com>
[bpt/emacs.git] / src / w32.c
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.
4
5 This file is part of GNU Emacs.
6
7 GNU Emacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
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.
16
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
19
20 /*
21 Geoff Voelker (voelker@cs.washington.edu) 7-29-94
22 */
23 #include <stddef.h> /* for offsetof */
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <io.h>
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <ctype.h>
30 #include <signal.h>
31 #include <sys/file.h>
32 #include <sys/time.h>
33 #include <sys/utime.h>
34 #include <mbstring.h> /* for _mbspbrk */
35
36 /* must include CRT headers *before* config.h */
37
38 #ifdef HAVE_CONFIG_H
39 #include <config.h>
40 #endif
41
42 #undef access
43 #undef chdir
44 #undef chmod
45 #undef creat
46 #undef ctime
47 #undef fopen
48 #undef link
49 #undef mkdir
50 #undef mktemp
51 #undef open
52 #undef rename
53 #undef rmdir
54 #undef unlink
55
56 #undef close
57 #undef dup
58 #undef dup2
59 #undef pipe
60 #undef read
61 #undef write
62
63 #undef strerror
64
65 #include "lisp.h"
66
67 #include <pwd.h>
68 #include <grp.h>
69
70 #ifdef __GNUC__
71 #define _ANONYMOUS_UNION
72 #define _ANONYMOUS_STRUCT
73 #endif
74 #include <windows.h>
75 #include <lmcons.h>
76 #include <shlobj.h>
77
78 #ifdef HAVE_SOCKETS /* TCP connection support, if kernel can do it */
79 #include <sys/socket.h>
80 #undef socket
81 #undef bind
82 #undef connect
83 #undef htons
84 #undef ntohs
85 #undef inet_addr
86 #undef gethostname
87 #undef gethostbyname
88 #undef getservbyname
89 #undef getpeername
90 #undef shutdown
91 #undef setsockopt
92 #undef listen
93 #undef getsockname
94 #undef accept
95 #undef recvfrom
96 #undef sendto
97 #endif
98
99 #include "w32.h"
100 #include "ndir.h"
101 #include "w32heap.h"
102 #include "systime.h"
103 #include "dispextern.h" /* for xstrcasecmp */
104
105 /* For serial_configure() and serial_open() */
106 #include "process.h"
107 /* From process.c */
108 extern Lisp_Object QCport, QCspeed, QCprocess;
109 extern Lisp_Object QCbytesize, QCstopbits, QCparity, Qodd, Qeven;
110 extern Lisp_Object QCflowcontrol, Qhw, Qsw, QCsummary;
111
112 typedef HRESULT (WINAPI * ShGetFolderPath_fn)
113 (IN HWND, IN int, IN HANDLE, IN DWORD, OUT char *);
114
115 void globals_of_w32 ();
116 static DWORD get_rid (PSID);
117
118 extern Lisp_Object Vw32_downcase_file_names;
119 extern Lisp_Object Vw32_generate_fake_inodes;
120 extern Lisp_Object Vw32_get_true_file_attributes;
121 /* Defined in process.c for its own purpose. */
122 extern Lisp_Object Qlocal;
123
124 extern int w32_num_mouse_buttons;
125
126 \f
127 /* Initialization states.
128
129 WARNING: If you add any more such variables for additional APIs,
130 you MUST add initialization for them to globals_of_w32
131 below. This is because these variables might get set
132 to non-NULL values during dumping, but the dumped Emacs
133 cannot reuse those values, because it could be run on a
134 different version of the OS, where API addresses are
135 different. */
136 static BOOL g_b_init_is_windows_9x;
137 static BOOL g_b_init_open_process_token;
138 static BOOL g_b_init_get_token_information;
139 static BOOL g_b_init_lookup_account_sid;
140 static BOOL g_b_init_get_sid_identifier_authority;
141 static BOOL g_b_init_get_sid_sub_authority;
142 static BOOL g_b_init_get_sid_sub_authority_count;
143 static BOOL g_b_init_get_file_security;
144 static BOOL g_b_init_get_security_descriptor_owner;
145 static BOOL g_b_init_get_security_descriptor_group;
146 static BOOL g_b_init_is_valid_sid;
147
148 /*
149 BEGIN: Wrapper functions around OpenProcessToken
150 and other functions in advapi32.dll that are only
151 supported in Windows NT / 2k / XP
152 */
153 /* ** Function pointer typedefs ** */
154 typedef BOOL (WINAPI * OpenProcessToken_Proc) (
155 HANDLE ProcessHandle,
156 DWORD DesiredAccess,
157 PHANDLE TokenHandle);
158 typedef BOOL (WINAPI * GetTokenInformation_Proc) (
159 HANDLE TokenHandle,
160 TOKEN_INFORMATION_CLASS TokenInformationClass,
161 LPVOID TokenInformation,
162 DWORD TokenInformationLength,
163 PDWORD ReturnLength);
164 typedef BOOL (WINAPI * GetProcessTimes_Proc) (
165 HANDLE process_handle,
166 LPFILETIME creation_time,
167 LPFILETIME exit_time,
168 LPFILETIME kernel_time,
169 LPFILETIME user_time);
170
171 GetProcessTimes_Proc get_process_times_fn = NULL;
172
173 #ifdef _UNICODE
174 const char * const LookupAccountSid_Name = "LookupAccountSidW";
175 const char * const GetFileSecurity_Name = "GetFileSecurityW";
176 #else
177 const char * const LookupAccountSid_Name = "LookupAccountSidA";
178 const char * const GetFileSecurity_Name = "GetFileSecurityA";
179 #endif
180 typedef BOOL (WINAPI * LookupAccountSid_Proc) (
181 LPCTSTR lpSystemName,
182 PSID Sid,
183 LPTSTR Name,
184 LPDWORD cbName,
185 LPTSTR DomainName,
186 LPDWORD cbDomainName,
187 PSID_NAME_USE peUse);
188 typedef PSID_IDENTIFIER_AUTHORITY (WINAPI * GetSidIdentifierAuthority_Proc) (
189 PSID pSid);
190 typedef PDWORD (WINAPI * GetSidSubAuthority_Proc) (
191 PSID pSid,
192 DWORD n);
193 typedef PUCHAR (WINAPI * GetSidSubAuthorityCount_Proc) (
194 PSID pSid);
195 typedef BOOL (WINAPI * GetFileSecurity_Proc) (
196 LPCTSTR lpFileName,
197 SECURITY_INFORMATION RequestedInformation,
198 PSECURITY_DESCRIPTOR pSecurityDescriptor,
199 DWORD nLength,
200 LPDWORD lpnLengthNeeded);
201 typedef BOOL (WINAPI * GetSecurityDescriptorOwner_Proc) (
202 PSECURITY_DESCRIPTOR pSecurityDescriptor,
203 PSID *pOwner,
204 LPBOOL lpbOwnerDefaulted);
205 typedef BOOL (WINAPI * GetSecurityDescriptorGroup_Proc) (
206 PSECURITY_DESCRIPTOR pSecurityDescriptor,
207 PSID *pGroup,
208 LPBOOL lpbGroupDefaulted);
209 typedef BOOL (WINAPI * IsValidSid_Proc) (
210 PSID sid);
211
212 /* ** A utility function ** */
213 static BOOL
214 is_windows_9x ()
215 {
216 static BOOL s_b_ret=0;
217 OSVERSIONINFO os_ver;
218 if (g_b_init_is_windows_9x == 0)
219 {
220 g_b_init_is_windows_9x = 1;
221 ZeroMemory(&os_ver, sizeof(OSVERSIONINFO));
222 os_ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
223 if (GetVersionEx (&os_ver))
224 {
225 s_b_ret = (os_ver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
226 }
227 }
228 return s_b_ret;
229 }
230
231 /* Get total user and system times for get-internal-run-time.
232 Returns a list of three integers if the times are provided by the OS
233 (NT derivatives), otherwise it returns the result of current-time. */
234 Lisp_Object
235 w32_get_internal_run_time ()
236 {
237 if (get_process_times_fn)
238 {
239 FILETIME create, exit, kernel, user;
240 HANDLE proc = GetCurrentProcess();
241 if ((*get_process_times_fn) (proc, &create, &exit, &kernel, &user))
242 {
243 LARGE_INTEGER user_int, kernel_int, total;
244 int microseconds;
245 user_int.LowPart = user.dwLowDateTime;
246 user_int.HighPart = user.dwHighDateTime;
247 kernel_int.LowPart = kernel.dwLowDateTime;
248 kernel_int.HighPart = kernel.dwHighDateTime;
249 total.QuadPart = user_int.QuadPart + kernel_int.QuadPart;
250 /* FILETIME is 100 nanosecond increments, Emacs only wants
251 microsecond resolution. */
252 total.QuadPart /= 10;
253 microseconds = total.QuadPart % 1000000;
254 total.QuadPart /= 1000000;
255
256 /* Sanity check to make sure we can represent the result. */
257 if (total.HighPart == 0)
258 {
259 int secs = total.LowPart;
260
261 return list3 (make_number ((secs >> 16) & 0xffff),
262 make_number (secs & 0xffff),
263 make_number (microseconds));
264 }
265 }
266 }
267
268 return Fcurrent_time ();
269 }
270
271 /* ** The wrapper functions ** */
272
273 BOOL WINAPI open_process_token (
274 HANDLE ProcessHandle,
275 DWORD DesiredAccess,
276 PHANDLE TokenHandle)
277 {
278 static OpenProcessToken_Proc s_pfn_Open_Process_Token = NULL;
279 HMODULE hm_advapi32 = NULL;
280 if (is_windows_9x () == TRUE)
281 {
282 return FALSE;
283 }
284 if (g_b_init_open_process_token == 0)
285 {
286 g_b_init_open_process_token = 1;
287 hm_advapi32 = LoadLibrary ("Advapi32.dll");
288 s_pfn_Open_Process_Token =
289 (OpenProcessToken_Proc) GetProcAddress (hm_advapi32, "OpenProcessToken");
290 }
291 if (s_pfn_Open_Process_Token == NULL)
292 {
293 return FALSE;
294 }
295 return (
296 s_pfn_Open_Process_Token (
297 ProcessHandle,
298 DesiredAccess,
299 TokenHandle)
300 );
301 }
302
303 BOOL WINAPI get_token_information (
304 HANDLE TokenHandle,
305 TOKEN_INFORMATION_CLASS TokenInformationClass,
306 LPVOID TokenInformation,
307 DWORD TokenInformationLength,
308 PDWORD ReturnLength)
309 {
310 static GetTokenInformation_Proc s_pfn_Get_Token_Information = NULL;
311 HMODULE hm_advapi32 = NULL;
312 if (is_windows_9x () == TRUE)
313 {
314 return FALSE;
315 }
316 if (g_b_init_get_token_information == 0)
317 {
318 g_b_init_get_token_information = 1;
319 hm_advapi32 = LoadLibrary ("Advapi32.dll");
320 s_pfn_Get_Token_Information =
321 (GetTokenInformation_Proc) GetProcAddress (hm_advapi32, "GetTokenInformation");
322 }
323 if (s_pfn_Get_Token_Information == NULL)
324 {
325 return FALSE;
326 }
327 return (
328 s_pfn_Get_Token_Information (
329 TokenHandle,
330 TokenInformationClass,
331 TokenInformation,
332 TokenInformationLength,
333 ReturnLength)
334 );
335 }
336
337 BOOL WINAPI lookup_account_sid (
338 LPCTSTR lpSystemName,
339 PSID Sid,
340 LPTSTR Name,
341 LPDWORD cbName,
342 LPTSTR DomainName,
343 LPDWORD cbDomainName,
344 PSID_NAME_USE peUse)
345 {
346 static LookupAccountSid_Proc s_pfn_Lookup_Account_Sid = NULL;
347 HMODULE hm_advapi32 = NULL;
348 if (is_windows_9x () == TRUE)
349 {
350 return FALSE;
351 }
352 if (g_b_init_lookup_account_sid == 0)
353 {
354 g_b_init_lookup_account_sid = 1;
355 hm_advapi32 = LoadLibrary ("Advapi32.dll");
356 s_pfn_Lookup_Account_Sid =
357 (LookupAccountSid_Proc) GetProcAddress (hm_advapi32, LookupAccountSid_Name);
358 }
359 if (s_pfn_Lookup_Account_Sid == NULL)
360 {
361 return FALSE;
362 }
363 return (
364 s_pfn_Lookup_Account_Sid (
365 lpSystemName,
366 Sid,
367 Name,
368 cbName,
369 DomainName,
370 cbDomainName,
371 peUse)
372 );
373 }
374
375 PSID_IDENTIFIER_AUTHORITY WINAPI get_sid_identifier_authority (
376 PSID pSid)
377 {
378 static GetSidIdentifierAuthority_Proc s_pfn_Get_Sid_Identifier_Authority = NULL;
379 HMODULE hm_advapi32 = NULL;
380 if (is_windows_9x () == TRUE)
381 {
382 return NULL;
383 }
384 if (g_b_init_get_sid_identifier_authority == 0)
385 {
386 g_b_init_get_sid_identifier_authority = 1;
387 hm_advapi32 = LoadLibrary ("Advapi32.dll");
388 s_pfn_Get_Sid_Identifier_Authority =
389 (GetSidIdentifierAuthority_Proc) GetProcAddress (
390 hm_advapi32, "GetSidIdentifierAuthority");
391 }
392 if (s_pfn_Get_Sid_Identifier_Authority == NULL)
393 {
394 return NULL;
395 }
396 return (s_pfn_Get_Sid_Identifier_Authority (pSid));
397 }
398
399 PDWORD WINAPI get_sid_sub_authority (
400 PSID pSid,
401 DWORD n)
402 {
403 static GetSidSubAuthority_Proc s_pfn_Get_Sid_Sub_Authority = NULL;
404 static DWORD zero = 0U;
405 HMODULE hm_advapi32 = NULL;
406 if (is_windows_9x () == TRUE)
407 {
408 return &zero;
409 }
410 if (g_b_init_get_sid_sub_authority == 0)
411 {
412 g_b_init_get_sid_sub_authority = 1;
413 hm_advapi32 = LoadLibrary ("Advapi32.dll");
414 s_pfn_Get_Sid_Sub_Authority =
415 (GetSidSubAuthority_Proc) GetProcAddress (
416 hm_advapi32, "GetSidSubAuthority");
417 }
418 if (s_pfn_Get_Sid_Sub_Authority == NULL)
419 {
420 return &zero;
421 }
422 return (s_pfn_Get_Sid_Sub_Authority (pSid, n));
423 }
424
425 PUCHAR WINAPI get_sid_sub_authority_count (
426 PSID pSid)
427 {
428 static GetSidSubAuthorityCount_Proc s_pfn_Get_Sid_Sub_Authority_Count = NULL;
429 static UCHAR zero = 0U;
430 HMODULE hm_advapi32 = NULL;
431 if (is_windows_9x () == TRUE)
432 {
433 return &zero;
434 }
435 if (g_b_init_get_sid_sub_authority_count == 0)
436 {
437 g_b_init_get_sid_sub_authority_count = 1;
438 hm_advapi32 = LoadLibrary ("Advapi32.dll");
439 s_pfn_Get_Sid_Sub_Authority_Count =
440 (GetSidSubAuthorityCount_Proc) GetProcAddress (
441 hm_advapi32, "GetSidSubAuthorityCount");
442 }
443 if (s_pfn_Get_Sid_Sub_Authority_Count == NULL)
444 {
445 return &zero;
446 }
447 return (s_pfn_Get_Sid_Sub_Authority_Count (pSid));
448 }
449
450 BOOL WINAPI get_file_security (
451 LPCTSTR lpFileName,
452 SECURITY_INFORMATION RequestedInformation,
453 PSECURITY_DESCRIPTOR pSecurityDescriptor,
454 DWORD nLength,
455 LPDWORD lpnLengthNeeded)
456 {
457 static GetFileSecurity_Proc s_pfn_Get_File_Security = NULL;
458 HMODULE hm_advapi32 = NULL;
459 if (is_windows_9x () == TRUE)
460 {
461 return FALSE;
462 }
463 if (g_b_init_get_file_security == 0)
464 {
465 g_b_init_get_file_security = 1;
466 hm_advapi32 = LoadLibrary ("Advapi32.dll");
467 s_pfn_Get_File_Security =
468 (GetFileSecurity_Proc) GetProcAddress (
469 hm_advapi32, GetFileSecurity_Name);
470 }
471 if (s_pfn_Get_File_Security == NULL)
472 {
473 return FALSE;
474 }
475 return (s_pfn_Get_File_Security (lpFileName, RequestedInformation,
476 pSecurityDescriptor, nLength,
477 lpnLengthNeeded));
478 }
479
480 BOOL WINAPI get_security_descriptor_owner (
481 PSECURITY_DESCRIPTOR pSecurityDescriptor,
482 PSID *pOwner,
483 LPBOOL lpbOwnerDefaulted)
484 {
485 static GetSecurityDescriptorOwner_Proc s_pfn_Get_Security_Descriptor_Owner = NULL;
486 HMODULE hm_advapi32 = NULL;
487 if (is_windows_9x () == TRUE)
488 {
489 return FALSE;
490 }
491 if (g_b_init_get_security_descriptor_owner == 0)
492 {
493 g_b_init_get_security_descriptor_owner = 1;
494 hm_advapi32 = LoadLibrary ("Advapi32.dll");
495 s_pfn_Get_Security_Descriptor_Owner =
496 (GetSecurityDescriptorOwner_Proc) GetProcAddress (
497 hm_advapi32, "GetSecurityDescriptorOwner");
498 }
499 if (s_pfn_Get_Security_Descriptor_Owner == NULL)
500 {
501 return FALSE;
502 }
503 return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor, pOwner,
504 lpbOwnerDefaulted));
505 }
506
507 BOOL WINAPI get_security_descriptor_group (
508 PSECURITY_DESCRIPTOR pSecurityDescriptor,
509 PSID *pGroup,
510 LPBOOL lpbGroupDefaulted)
511 {
512 static GetSecurityDescriptorGroup_Proc s_pfn_Get_Security_Descriptor_Group = NULL;
513 HMODULE hm_advapi32 = NULL;
514 if (is_windows_9x () == TRUE)
515 {
516 return FALSE;
517 }
518 if (g_b_init_get_security_descriptor_group == 0)
519 {
520 g_b_init_get_security_descriptor_group = 1;
521 hm_advapi32 = LoadLibrary ("Advapi32.dll");
522 s_pfn_Get_Security_Descriptor_Group =
523 (GetSecurityDescriptorGroup_Proc) GetProcAddress (
524 hm_advapi32, "GetSecurityDescriptorGroup");
525 }
526 if (s_pfn_Get_Security_Descriptor_Group == NULL)
527 {
528 return FALSE;
529 }
530 return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor, pGroup,
531 lpbGroupDefaulted));
532 }
533
534 BOOL WINAPI is_valid_sid (
535 PSID sid)
536 {
537 static IsValidSid_Proc s_pfn_Is_Valid_Sid = NULL;
538 HMODULE hm_advapi32 = NULL;
539 if (is_windows_9x () == TRUE)
540 {
541 return FALSE;
542 }
543 if (g_b_init_is_valid_sid == 0)
544 {
545 g_b_init_is_valid_sid = 1;
546 hm_advapi32 = LoadLibrary ("Advapi32.dll");
547 s_pfn_Is_Valid_Sid =
548 (IsValidSid_Proc) GetProcAddress (
549 hm_advapi32, "IsValidSid");
550 }
551 if (s_pfn_Is_Valid_Sid == NULL)
552 {
553 return FALSE;
554 }
555 return (s_pfn_Is_Valid_Sid (sid));
556 }
557
558 /*
559 END: Wrapper functions around OpenProcessToken
560 and other functions in advapi32.dll that are only
561 supported in Windows NT / 2k / XP
562 */
563
564 \f
565 /* Equivalent of strerror for W32 error codes. */
566 char *
567 w32_strerror (int error_no)
568 {
569 static char buf[500];
570
571 if (error_no == 0)
572 error_no = GetLastError ();
573
574 buf[0] = '\0';
575 if (!FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL,
576 error_no,
577 0, /* choose most suitable language */
578 buf, sizeof (buf), NULL))
579 sprintf (buf, "w32 error %u", error_no);
580 return buf;
581 }
582
583 /* Return 1 if P is a valid pointer to an object of size SIZE. Return
584 0 if P is NOT a valid pointer. Return -1 if we cannot validate P.
585
586 This is called from alloc.c:valid_pointer_p. */
587 int
588 w32_valid_pointer_p (void *p, int size)
589 {
590 SIZE_T done;
591 HANDLE h = OpenProcess (PROCESS_VM_READ, FALSE, GetCurrentProcessId ());
592
593 if (h)
594 {
595 unsigned char *buf = alloca (size);
596 int retval = ReadProcessMemory (h, p, buf, size, &done);
597
598 CloseHandle (h);
599 return retval;
600 }
601 else
602 return -1;
603 }
604
605 static char startup_dir[MAXPATHLEN];
606
607 /* Get the current working directory. */
608 char *
609 getwd (char *dir)
610 {
611 #if 0
612 if (GetCurrentDirectory (MAXPATHLEN, dir) > 0)
613 return dir;
614 return NULL;
615 #else
616 /* Emacs doesn't actually change directory itself, and we want to
617 force our real wd to be where emacs.exe is to avoid unnecessary
618 conflicts when trying to rename or delete directories. */
619 strcpy (dir, startup_dir);
620 return dir;
621 #endif
622 }
623
624 #ifndef HAVE_SOCKETS
625 /* Emulate gethostname. */
626 int
627 gethostname (char *buffer, int size)
628 {
629 /* NT only allows small host names, so the buffer is
630 certainly large enough. */
631 return !GetComputerName (buffer, &size);
632 }
633 #endif /* HAVE_SOCKETS */
634
635 /* Emulate getloadavg. */
636 int
637 getloadavg (double loadavg[], int nelem)
638 {
639 int i;
640
641 /* A faithful emulation is going to have to be saved for a rainy day. */
642 for (i = 0; i < nelem; i++)
643 {
644 loadavg[i] = 0.0;
645 }
646 return i;
647 }
648
649 /* Emulate getpwuid, getpwnam and others. */
650
651 #define PASSWD_FIELD_SIZE 256
652
653 static char dflt_passwd_name[PASSWD_FIELD_SIZE];
654 static char dflt_passwd_passwd[PASSWD_FIELD_SIZE];
655 static char dflt_passwd_gecos[PASSWD_FIELD_SIZE];
656 static char dflt_passwd_dir[PASSWD_FIELD_SIZE];
657 static char dflt_passwd_shell[PASSWD_FIELD_SIZE];
658
659 static struct passwd dflt_passwd =
660 {
661 dflt_passwd_name,
662 dflt_passwd_passwd,
663 0,
664 0,
665 0,
666 dflt_passwd_gecos,
667 dflt_passwd_dir,
668 dflt_passwd_shell,
669 };
670
671 static char dflt_group_name[GNLEN+1];
672
673 static struct group dflt_group =
674 {
675 /* When group information is not available, we return this as the
676 group for all files. */
677 dflt_group_name,
678 0,
679 };
680
681 int
682 getuid ()
683 {
684 return dflt_passwd.pw_uid;
685 }
686
687 int
688 geteuid ()
689 {
690 /* I could imagine arguing for checking to see whether the user is
691 in the Administrators group and returning a UID of 0 for that
692 case, but I don't know how wise that would be in the long run. */
693 return getuid ();
694 }
695
696 int
697 getgid ()
698 {
699 return dflt_passwd.pw_gid;
700 }
701
702 int
703 getegid ()
704 {
705 return getgid ();
706 }
707
708 struct passwd *
709 getpwuid (int uid)
710 {
711 if (uid == dflt_passwd.pw_uid)
712 return &dflt_passwd;
713 return NULL;
714 }
715
716 struct group *
717 getgrgid (gid_t gid)
718 {
719 return &dflt_group;
720 }
721
722 struct passwd *
723 getpwnam (char *name)
724 {
725 struct passwd *pw;
726
727 pw = getpwuid (getuid ());
728 if (!pw)
729 return pw;
730
731 if (xstrcasecmp (name, pw->pw_name))
732 return NULL;
733
734 return pw;
735 }
736
737 void
738 init_user_info ()
739 {
740 /* Find the user's real name by opening the process token and
741 looking up the name associated with the user-sid in that token.
742
743 Use the relative portion of the identifier authority value from
744 the user-sid as the user id value (same for group id using the
745 primary group sid from the process token). */
746
747 char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
748 DWORD ulength = sizeof (uname), dlength = sizeof (domain), trash;
749 DWORD glength = sizeof (gname);
750 HANDLE token = NULL;
751 SID_NAME_USE user_type;
752 unsigned char buf[1024];
753 TOKEN_USER user_token;
754 TOKEN_PRIMARY_GROUP group_token;
755
756 if (open_process_token (GetCurrentProcess (), TOKEN_QUERY, &token)
757 && get_token_information (token, TokenUser,
758 (PVOID)buf, sizeof (buf), &trash)
759 && (memcpy (&user_token, buf, sizeof (user_token)),
760 lookup_account_sid (NULL, user_token.User.Sid, uname, &ulength,
761 domain, &dlength, &user_type)))
762 {
763 strcpy (dflt_passwd.pw_name, uname);
764 /* Determine a reasonable uid value. */
765 if (xstrcasecmp ("administrator", uname) == 0)
766 {
767 dflt_passwd.pw_uid = 500; /* well-known Administrator uid */
768 dflt_passwd.pw_gid = 513; /* well-known None gid */
769 }
770 else
771 {
772 /* Use the last sub-authority value of the RID, the relative
773 portion of the SID, as user/group ID. */
774 dflt_passwd.pw_uid = get_rid (user_token.User.Sid);
775
776 /* Get group id and name. */
777 if (get_token_information (token, TokenPrimaryGroup,
778 (PVOID)buf, sizeof (buf), &trash))
779 {
780 memcpy (&group_token, buf, sizeof (group_token));
781 dflt_passwd.pw_gid = get_rid (group_token.PrimaryGroup);
782 dlength = sizeof (domain);
783 if (lookup_account_sid (NULL, group_token.PrimaryGroup,
784 gname, &glength, NULL, &dlength,
785 &user_type))
786 strcpy (dflt_group_name, gname);
787 }
788 else
789 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
790 }
791 }
792 /* If security calls are not supported (presumably because we
793 are running under Windows 95), fallback to this. */
794 else if (GetUserName (uname, &ulength))
795 {
796 strcpy (dflt_passwd.pw_name, uname);
797 if (xstrcasecmp ("administrator", uname) == 0)
798 dflt_passwd.pw_uid = 0;
799 else
800 dflt_passwd.pw_uid = 123;
801 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
802 }
803 else
804 {
805 strcpy (dflt_passwd.pw_name, "unknown");
806 dflt_passwd.pw_uid = 123;
807 dflt_passwd.pw_gid = 123;
808 }
809 dflt_group.gr_gid = dflt_passwd.pw_gid;
810
811 /* Ensure HOME and SHELL are defined. */
812 if (getenv ("HOME") == NULL)
813 abort ();
814 if (getenv ("SHELL") == NULL)
815 abort ();
816
817 /* Set dir and shell from environment variables. */
818 strcpy (dflt_passwd.pw_dir, getenv ("HOME"));
819 strcpy (dflt_passwd.pw_shell, getenv ("SHELL"));
820
821 if (token)
822 CloseHandle (token);
823 }
824
825 int
826 random ()
827 {
828 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
829 return ((rand () << 15) | rand ());
830 }
831
832 void
833 srandom (int seed)
834 {
835 srand (seed);
836 }
837
838
839 /* Normalize filename by converting all path separators to
840 the specified separator. Also conditionally convert upper
841 case path name components to lower case. */
842
843 static void
844 normalize_filename (fp, path_sep)
845 register char *fp;
846 char path_sep;
847 {
848 char sep;
849 char *elem;
850
851 /* Always lower-case drive letters a-z, even if the filesystem
852 preserves case in filenames.
853 This is so filenames can be compared by string comparison
854 functions that are case-sensitive. Even case-preserving filesystems
855 do not distinguish case in drive letters. */
856 if (fp[1] == ':' && *fp >= 'A' && *fp <= 'Z')
857 {
858 *fp += 'a' - 'A';
859 fp += 2;
860 }
861
862 if (NILP (Vw32_downcase_file_names))
863 {
864 while (*fp)
865 {
866 if (*fp == '/' || *fp == '\\')
867 *fp = path_sep;
868 fp++;
869 }
870 return;
871 }
872
873 sep = path_sep; /* convert to this path separator */
874 elem = fp; /* start of current path element */
875
876 do {
877 if (*fp >= 'a' && *fp <= 'z')
878 elem = 0; /* don't convert this element */
879
880 if (*fp == 0 || *fp == ':')
881 {
882 sep = *fp; /* restore current separator (or 0) */
883 *fp = '/'; /* after conversion of this element */
884 }
885
886 if (*fp == '/' || *fp == '\\')
887 {
888 if (elem && elem != fp)
889 {
890 *fp = 0; /* temporary end of string */
891 _strlwr (elem); /* while we convert to lower case */
892 }
893 *fp = sep; /* convert (or restore) path separator */
894 elem = fp + 1; /* next element starts after separator */
895 sep = path_sep;
896 }
897 } while (*fp++);
898 }
899
900 /* Destructively turn backslashes into slashes. */
901 void
902 dostounix_filename (p)
903 register char *p;
904 {
905 normalize_filename (p, '/');
906 }
907
908 /* Destructively turn slashes into backslashes. */
909 void
910 unixtodos_filename (p)
911 register char *p;
912 {
913 normalize_filename (p, '\\');
914 }
915
916 /* Remove all CR's that are followed by a LF.
917 (From msdos.c...probably should figure out a way to share it,
918 although this code isn't going to ever change.) */
919 int
920 crlf_to_lf (n, buf)
921 register int n;
922 register unsigned char *buf;
923 {
924 unsigned char *np = buf;
925 unsigned char *startp = buf;
926 unsigned char *endp = buf + n;
927
928 if (n == 0)
929 return n;
930 while (buf < endp - 1)
931 {
932 if (*buf == 0x0d)
933 {
934 if (*(++buf) != 0x0a)
935 *np++ = 0x0d;
936 }
937 else
938 *np++ = *buf++;
939 }
940 if (buf < endp)
941 *np++ = *buf++;
942 return np - startp;
943 }
944
945 /* Parse the root part of file name, if present. Return length and
946 optionally store pointer to char after root. */
947 static int
948 parse_root (char * name, char ** pPath)
949 {
950 char * start = name;
951
952 if (name == NULL)
953 return 0;
954
955 /* find the root name of the volume if given */
956 if (isalpha (name[0]) && name[1] == ':')
957 {
958 /* skip past drive specifier */
959 name += 2;
960 if (IS_DIRECTORY_SEP (name[0]))
961 name++;
962 }
963 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
964 {
965 int slashes = 2;
966 name += 2;
967 do
968 {
969 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
970 break;
971 name++;
972 }
973 while ( *name );
974 if (IS_DIRECTORY_SEP (name[0]))
975 name++;
976 }
977
978 if (pPath)
979 *pPath = name;
980
981 return name - start;
982 }
983
984 /* Get long base name for name; name is assumed to be absolute. */
985 static int
986 get_long_basename (char * name, char * buf, int size)
987 {
988 WIN32_FIND_DATA find_data;
989 HANDLE dir_handle;
990 int len = 0;
991
992 /* must be valid filename, no wild cards or other invalid characters */
993 if (_mbspbrk (name, "*?|<>\""))
994 return 0;
995
996 dir_handle = FindFirstFile (name, &find_data);
997 if (dir_handle != INVALID_HANDLE_VALUE)
998 {
999 if ((len = strlen (find_data.cFileName)) < size)
1000 memcpy (buf, find_data.cFileName, len + 1);
1001 else
1002 len = 0;
1003 FindClose (dir_handle);
1004 }
1005 return len;
1006 }
1007
1008 /* Get long name for file, if possible (assumed to be absolute). */
1009 BOOL
1010 w32_get_long_filename (char * name, char * buf, int size)
1011 {
1012 char * o = buf;
1013 char * p;
1014 char * q;
1015 char full[ MAX_PATH ];
1016 int len;
1017
1018 len = strlen (name);
1019 if (len >= MAX_PATH)
1020 return FALSE;
1021
1022 /* Use local copy for destructive modification. */
1023 memcpy (full, name, len+1);
1024 unixtodos_filename (full);
1025
1026 /* Copy root part verbatim. */
1027 len = parse_root (full, &p);
1028 memcpy (o, full, len);
1029 o += len;
1030 *o = '\0';
1031 size -= len;
1032
1033 while (p != NULL && *p)
1034 {
1035 q = p;
1036 p = strchr (q, '\\');
1037 if (p) *p = '\0';
1038 len = get_long_basename (full, o, size);
1039 if (len > 0)
1040 {
1041 o += len;
1042 size -= len;
1043 if (p != NULL)
1044 {
1045 *p++ = '\\';
1046 if (size < 2)
1047 return FALSE;
1048 *o++ = '\\';
1049 size--;
1050 *o = '\0';
1051 }
1052 }
1053 else
1054 return FALSE;
1055 }
1056
1057 return TRUE;
1058 }
1059
1060 int
1061 is_unc_volume (const char *filename)
1062 {
1063 const char *ptr = filename;
1064
1065 if (!IS_DIRECTORY_SEP (ptr[0]) || !IS_DIRECTORY_SEP (ptr[1]) || !ptr[2])
1066 return 0;
1067
1068 if (_mbspbrk (ptr + 2, "*?|<>\"\\/"))
1069 return 0;
1070
1071 return 1;
1072 }
1073
1074 /* Routines that are no-ops on NT but are defined to get Emacs to compile. */
1075
1076 int
1077 sigsetmask (int signal_mask)
1078 {
1079 return 0;
1080 }
1081
1082 int
1083 sigmask (int sig)
1084 {
1085 return 0;
1086 }
1087
1088 int
1089 sigblock (int sig)
1090 {
1091 return 0;
1092 }
1093
1094 int
1095 sigunblock (int sig)
1096 {
1097 return 0;
1098 }
1099
1100 int
1101 setpgrp (int pid, int gid)
1102 {
1103 return 0;
1104 }
1105
1106 int
1107 alarm (int seconds)
1108 {
1109 return 0;
1110 }
1111
1112 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
1113
1114 LPBYTE
1115 w32_get_resource (key, lpdwtype)
1116 char *key;
1117 LPDWORD lpdwtype;
1118 {
1119 LPBYTE lpvalue;
1120 HKEY hrootkey = NULL;
1121 DWORD cbData;
1122
1123 /* Check both the current user and the local machine to see if
1124 we have any resources. */
1125
1126 if (RegOpenKeyEx (HKEY_CURRENT_USER, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
1127 {
1128 lpvalue = NULL;
1129
1130 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
1131 && (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL
1132 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
1133 {
1134 RegCloseKey (hrootkey);
1135 return (lpvalue);
1136 }
1137
1138 xfree (lpvalue);
1139
1140 RegCloseKey (hrootkey);
1141 }
1142
1143 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
1144 {
1145 lpvalue = NULL;
1146
1147 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
1148 && (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL
1149 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
1150 {
1151 RegCloseKey (hrootkey);
1152 return (lpvalue);
1153 }
1154
1155 xfree (lpvalue);
1156
1157 RegCloseKey (hrootkey);
1158 }
1159
1160 return (NULL);
1161 }
1162
1163 char *get_emacs_configuration (void);
1164 extern Lisp_Object Vsystem_configuration;
1165
1166 void
1167 init_environment (char ** argv)
1168 {
1169 static const char * const tempdirs[] = {
1170 "$TMPDIR", "$TEMP", "$TMP", "c:/"
1171 };
1172
1173 int i;
1174
1175 const int imax = sizeof (tempdirs) / sizeof (tempdirs[0]);
1176
1177 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
1178 temporary files and assume "/tmp" if $TMPDIR is unset, which
1179 will break on DOS/Windows. Refuse to work if we cannot find
1180 a directory, not even "c:/", usable for that purpose. */
1181 for (i = 0; i < imax ; i++)
1182 {
1183 const char *tmp = tempdirs[i];
1184
1185 if (*tmp == '$')
1186 tmp = getenv (tmp + 1);
1187 /* Note that `access' can lie to us if the directory resides on a
1188 read-only filesystem, like CD-ROM or a write-protected floppy.
1189 The only way to be really sure is to actually create a file and
1190 see if it succeeds. But I think that's too much to ask. */
1191 if (tmp && _access (tmp, D_OK) == 0)
1192 {
1193 char * var = alloca (strlen (tmp) + 8);
1194 sprintf (var, "TMPDIR=%s", tmp);
1195 _putenv (strdup (var));
1196 break;
1197 }
1198 }
1199 if (i >= imax)
1200 cmd_error_internal
1201 (Fcons (Qerror,
1202 Fcons (build_string ("no usable temporary directories found!!"),
1203 Qnil)),
1204 "While setting TMPDIR: ");
1205
1206 /* Check for environment variables and use registry settings if they
1207 don't exist. Fallback on default values where applicable. */
1208 {
1209 int i;
1210 LPBYTE lpval;
1211 DWORD dwType;
1212 char locale_name[32];
1213 struct stat ignored;
1214 char default_home[MAX_PATH];
1215
1216 static const struct env_entry
1217 {
1218 char * name;
1219 char * def_value;
1220 } dflt_envvars[] =
1221 {
1222 {"HOME", "C:/"},
1223 {"PRELOAD_WINSOCK", NULL},
1224 {"emacs_dir", "C:/emacs"},
1225 {"EMACSLOADPATH", "%emacs_dir%/site-lisp;%emacs_dir%/../site-lisp;%emacs_dir%/lisp;%emacs_dir%/leim"},
1226 {"SHELL", "%emacs_dir%/bin/cmdproxy.exe"},
1227 {"EMACSDATA", "%emacs_dir%/etc"},
1228 {"EMACSPATH", "%emacs_dir%/bin"},
1229 /* We no longer set INFOPATH because Info-default-directory-list
1230 is then ignored. */
1231 /* {"INFOPATH", "%emacs_dir%/info"}, */
1232 {"EMACSDOC", "%emacs_dir%/etc"},
1233 {"TERM", "cmd"},
1234 {"LANG", NULL},
1235 };
1236
1237 #define N_ENV_VARS sizeof(dflt_envvars)/sizeof(dflt_envvars[0])
1238
1239 /* We need to copy dflt_envvars[] and work on the copy because we
1240 don't want the dumped Emacs to inherit the values of
1241 environment variables we saw during dumping (which could be on
1242 a different system). The defaults above must be left intact. */
1243 struct env_entry env_vars[N_ENV_VARS];
1244
1245 for (i = 0; i < N_ENV_VARS; i++)
1246 env_vars[i] = dflt_envvars[i];
1247
1248 /* For backwards compatibility, check if a .emacs file exists in C:/
1249 If not, then we can try to default to the appdata directory under the
1250 user's profile, which is more likely to be writable. */
1251 if (stat ("C:/.emacs", &ignored) < 0)
1252 {
1253 HRESULT profile_result;
1254 /* Dynamically load ShGetFolderPath, as it won't exist on versions
1255 of Windows 95 and NT4 that have not been updated to include
1256 MSIE 5. Also we don't link with shell32.dll by default. */
1257 HMODULE shell32_dll;
1258 ShGetFolderPath_fn get_folder_path;
1259 shell32_dll = GetModuleHandle ("shell32.dll");
1260 get_folder_path = (ShGetFolderPath_fn)
1261 GetProcAddress (shell32_dll, "SHGetFolderPathA");
1262
1263 if (get_folder_path != NULL)
1264 {
1265 profile_result = get_folder_path (NULL, CSIDL_APPDATA, NULL,
1266 0, default_home);
1267
1268 /* If we can't get the appdata dir, revert to old behaviour. */
1269 if (profile_result == S_OK)
1270 env_vars[0].def_value = default_home;
1271 }
1272
1273 /* Unload shell32.dll, it is not needed anymore. */
1274 FreeLibrary (shell32_dll);
1275 }
1276
1277 /* Get default locale info and use it for LANG. */
1278 if (GetLocaleInfo (LOCALE_USER_DEFAULT,
1279 LOCALE_SABBREVLANGNAME | LOCALE_USE_CP_ACP,
1280 locale_name, sizeof (locale_name)))
1281 {
1282 for (i = 0; i < N_ENV_VARS; i++)
1283 {
1284 if (strcmp (env_vars[i].name, "LANG") == 0)
1285 {
1286 env_vars[i].def_value = locale_name;
1287 break;
1288 }
1289 }
1290 }
1291
1292 #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
1293
1294 /* Treat emacs_dir specially: set it unconditionally based on our
1295 location, if it appears that we are running from the bin subdir
1296 of a standard installation. */
1297 {
1298 char *p;
1299 char modname[MAX_PATH];
1300
1301 if (!GetModuleFileName (NULL, modname, MAX_PATH))
1302 abort ();
1303 if ((p = strrchr (modname, '\\')) == NULL)
1304 abort ();
1305 *p = 0;
1306
1307 if ((p = strrchr (modname, '\\')) && xstrcasecmp (p, "\\bin") == 0)
1308 {
1309 char buf[SET_ENV_BUF_SIZE];
1310
1311 *p = 0;
1312 for (p = modname; *p; p++)
1313 if (*p == '\\') *p = '/';
1314
1315 _snprintf (buf, sizeof(buf)-1, "emacs_dir=%s", modname);
1316 _putenv (strdup (buf));
1317 }
1318 /* Handle running emacs from the build directory: src/oo-spd/i386/ */
1319
1320 /* FIXME: should use substring of get_emacs_configuration ().
1321 But I don't think the Windows build supports alpha, mips etc
1322 anymore, so have taken the easy option for now. */
1323 else if (p && xstrcasecmp (p, "\\i386") == 0)
1324 {
1325 *p = 0;
1326 p = strrchr (modname, '\\');
1327 if (p != NULL)
1328 {
1329 *p = 0;
1330 p = strrchr (modname, '\\');
1331 if (p && xstrcasecmp (p, "\\src") == 0)
1332 {
1333 char buf[SET_ENV_BUF_SIZE];
1334
1335 *p = 0;
1336 for (p = modname; *p; p++)
1337 if (*p == '\\') *p = '/';
1338
1339 _snprintf (buf, sizeof(buf)-1, "emacs_dir=%s", modname);
1340 _putenv (strdup (buf));
1341 }
1342 }
1343 }
1344 }
1345
1346 for (i = 0; i < N_ENV_VARS; i++)
1347 {
1348 if (!getenv (env_vars[i].name))
1349 {
1350 int dont_free = 0;
1351
1352 if ((lpval = w32_get_resource (env_vars[i].name, &dwType)) == NULL
1353 /* Also ignore empty environment variables. */
1354 || *lpval == 0)
1355 {
1356 xfree (lpval);
1357 lpval = env_vars[i].def_value;
1358 dwType = REG_EXPAND_SZ;
1359 dont_free = 1;
1360 }
1361
1362 if (lpval)
1363 {
1364 char buf1[SET_ENV_BUF_SIZE], buf2[SET_ENV_BUF_SIZE];
1365
1366 if (dwType == REG_EXPAND_SZ)
1367 ExpandEnvironmentStrings ((LPSTR) lpval, buf1, sizeof(buf1));
1368 else if (dwType == REG_SZ)
1369 strcpy (buf1, lpval);
1370 if (dwType == REG_EXPAND_SZ || dwType == REG_SZ)
1371 {
1372 _snprintf (buf2, sizeof(buf2)-1, "%s=%s", env_vars[i].name,
1373 buf1);
1374 _putenv (strdup (buf2));
1375 }
1376
1377 if (!dont_free)
1378 xfree (lpval);
1379 }
1380 }
1381 }
1382 }
1383
1384 /* Rebuild system configuration to reflect invoking system. */
1385 Vsystem_configuration = build_string (EMACS_CONFIGURATION);
1386
1387 /* Another special case: on NT, the PATH variable is actually named
1388 "Path" although cmd.exe (perhaps NT itself) arranges for
1389 environment variable lookup and setting to be case insensitive.
1390 However, Emacs assumes a fully case sensitive environment, so we
1391 need to change "Path" to "PATH" to match the expectations of
1392 various elisp packages. We do this by the sneaky method of
1393 modifying the string in the C runtime environ entry.
1394
1395 The same applies to COMSPEC. */
1396 {
1397 char ** envp;
1398
1399 for (envp = environ; *envp; envp++)
1400 if (_strnicmp (*envp, "PATH=", 5) == 0)
1401 memcpy (*envp, "PATH=", 5);
1402 else if (_strnicmp (*envp, "COMSPEC=", 8) == 0)
1403 memcpy (*envp, "COMSPEC=", 8);
1404 }
1405
1406 /* Remember the initial working directory for getwd, then make the
1407 real wd be the location of emacs.exe to avoid conflicts when
1408 renaming or deleting directories. (We also don't call chdir when
1409 running subprocesses for the same reason.) */
1410 if (!GetCurrentDirectory (MAXPATHLEN, startup_dir))
1411 abort ();
1412
1413 {
1414 char *p;
1415 static char modname[MAX_PATH];
1416
1417 if (!GetModuleFileName (NULL, modname, MAX_PATH))
1418 abort ();
1419 if ((p = strrchr (modname, '\\')) == NULL)
1420 abort ();
1421 *p = 0;
1422
1423 SetCurrentDirectory (modname);
1424
1425 /* Ensure argv[0] has the full path to Emacs. */
1426 *p = '\\';
1427 argv[0] = modname;
1428 }
1429
1430 /* Determine if there is a middle mouse button, to allow parse_button
1431 to decide whether right mouse events should be mouse-2 or
1432 mouse-3. */
1433 w32_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);
1434
1435 init_user_info ();
1436 }
1437
1438 char *
1439 emacs_root_dir (void)
1440 {
1441 static char root_dir[FILENAME_MAX];
1442 const char *p;
1443
1444 p = getenv ("emacs_dir");
1445 if (p == NULL)
1446 abort ();
1447 strcpy (root_dir, p);
1448 root_dir[parse_root (root_dir, NULL)] = '\0';
1449 dostounix_filename (root_dir);
1450 return root_dir;
1451 }
1452
1453 /* We don't have scripts to automatically determine the system configuration
1454 for Emacs before it's compiled, and we don't want to have to make the
1455 user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
1456 routine. */
1457
1458 char *
1459 get_emacs_configuration (void)
1460 {
1461 char *arch, *oem, *os;
1462 int build_num;
1463 static char configuration_buffer[32];
1464
1465 /* Determine the processor type. */
1466 switch (get_processor_type ())
1467 {
1468
1469 #ifdef PROCESSOR_INTEL_386
1470 case PROCESSOR_INTEL_386:
1471 case PROCESSOR_INTEL_486:
1472 case PROCESSOR_INTEL_PENTIUM:
1473 arch = "i386";
1474 break;
1475 #endif
1476
1477 #ifdef PROCESSOR_MIPS_R2000
1478 case PROCESSOR_MIPS_R2000:
1479 case PROCESSOR_MIPS_R3000:
1480 case PROCESSOR_MIPS_R4000:
1481 arch = "mips";
1482 break;
1483 #endif
1484
1485 #ifdef PROCESSOR_ALPHA_21064
1486 case PROCESSOR_ALPHA_21064:
1487 arch = "alpha";
1488 break;
1489 #endif
1490
1491 default:
1492 arch = "unknown";
1493 break;
1494 }
1495
1496 /* Use the OEM field to reflect the compiler/library combination. */
1497 #ifdef _MSC_VER
1498 #define COMPILER_NAME "msvc"
1499 #else
1500 #ifdef __GNUC__
1501 #define COMPILER_NAME "mingw"
1502 #else
1503 #define COMPILER_NAME "unknown"
1504 #endif
1505 #endif
1506 oem = COMPILER_NAME;
1507
1508 switch (osinfo_cache.dwPlatformId) {
1509 case VER_PLATFORM_WIN32_NT:
1510 os = "nt";
1511 build_num = osinfo_cache.dwBuildNumber;
1512 break;
1513 case VER_PLATFORM_WIN32_WINDOWS:
1514 if (osinfo_cache.dwMinorVersion == 0) {
1515 os = "windows95";
1516 } else {
1517 os = "windows98";
1518 }
1519 build_num = LOWORD (osinfo_cache.dwBuildNumber);
1520 break;
1521 case VER_PLATFORM_WIN32s:
1522 /* Not supported, should not happen. */
1523 os = "windows32s";
1524 build_num = LOWORD (osinfo_cache.dwBuildNumber);
1525 break;
1526 default:
1527 os = "unknown";
1528 build_num = 0;
1529 break;
1530 }
1531
1532 if (osinfo_cache.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1533 sprintf (configuration_buffer, "%s-%s-%s%d.%d.%d", arch, oem, os,
1534 get_w32_major_version (), get_w32_minor_version (), build_num);
1535 } else {
1536 sprintf (configuration_buffer, "%s-%s-%s.%d", arch, oem, os, build_num);
1537 }
1538
1539 return configuration_buffer;
1540 }
1541
1542 char *
1543 get_emacs_configuration_options (void)
1544 {
1545 static char options_buffer[256];
1546
1547 /* Work out the effective configure options for this build. */
1548 #ifdef _MSC_VER
1549 #define COMPILER_VERSION "--with-msvc (%d.%02d)", _MSC_VER / 100, _MSC_VER % 100
1550 #else
1551 #ifdef __GNUC__
1552 #define COMPILER_VERSION "--with-gcc (%d.%d)", __GNUC__, __GNUC_MINOR__
1553 #else
1554 #define COMPILER_VERSION ""
1555 #endif
1556 #endif
1557
1558 sprintf (options_buffer, COMPILER_VERSION);
1559 #ifdef EMACSDEBUG
1560 strcat (options_buffer, " --no-opt");
1561 #endif
1562 #ifdef USER_CFLAGS
1563 strcat (options_buffer, " --cflags");
1564 strcat (options_buffer, USER_CFLAGS);
1565 #endif
1566 #ifdef USER_LDFLAGS
1567 strcat (options_buffer, " --ldflags");
1568 strcat (options_buffer, USER_LDFLAGS);
1569 #endif
1570 return options_buffer;
1571 }
1572
1573
1574 #include <sys/timeb.h>
1575
1576 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
1577 void
1578 gettimeofday (struct timeval *tv, struct timezone *tz)
1579 {
1580 struct _timeb tb;
1581 _ftime (&tb);
1582
1583 tv->tv_sec = tb.time;
1584 tv->tv_usec = tb.millitm * 1000L;
1585 if (tz)
1586 {
1587 tz->tz_minuteswest = tb.timezone; /* minutes west of Greenwich */
1588 tz->tz_dsttime = tb.dstflag; /* type of dst correction */
1589 }
1590 }
1591
1592 /* ------------------------------------------------------------------------- */
1593 /* IO support and wrapper functions for W32 API. */
1594 /* ------------------------------------------------------------------------- */
1595
1596 /* Place a wrapper around the MSVC version of ctime. It returns NULL
1597 on network directories, so we handle that case here.
1598 (Ulrich Leodolter, 1/11/95). */
1599 char *
1600 sys_ctime (const time_t *t)
1601 {
1602 char *str = (char *) ctime (t);
1603 return (str ? str : "Sun Jan 01 00:00:00 1970");
1604 }
1605
1606 /* Emulate sleep...we could have done this with a define, but that
1607 would necessitate including windows.h in the files that used it.
1608 This is much easier. */
1609 void
1610 sys_sleep (int seconds)
1611 {
1612 Sleep (seconds * 1000);
1613 }
1614
1615 /* Internal MSVC functions for low-level descriptor munging */
1616 extern int __cdecl _set_osfhnd (int fd, long h);
1617 extern int __cdecl _free_osfhnd (int fd);
1618
1619 /* parallel array of private info on file handles */
1620 filedesc fd_info [ MAXDESC ];
1621
1622 typedef struct volume_info_data {
1623 struct volume_info_data * next;
1624
1625 /* time when info was obtained */
1626 DWORD timestamp;
1627
1628 /* actual volume info */
1629 char * root_dir;
1630 DWORD serialnum;
1631 DWORD maxcomp;
1632 DWORD flags;
1633 char * name;
1634 char * type;
1635 } volume_info_data;
1636
1637 /* Global referenced by various functions. */
1638 static volume_info_data volume_info;
1639
1640 /* Vector to indicate which drives are local and fixed (for which cached
1641 data never expires). */
1642 static BOOL fixed_drives[26];
1643
1644 /* Consider cached volume information to be stale if older than 10s,
1645 at least for non-local drives. Info for fixed drives is never stale. */
1646 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
1647 #define VOLINFO_STILL_VALID( root_dir, info ) \
1648 ( ( isalpha (root_dir[0]) && \
1649 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
1650 || GetTickCount () - info->timestamp < 10000 )
1651
1652 /* Cache support functions. */
1653
1654 /* Simple linked list with linear search is sufficient. */
1655 static volume_info_data *volume_cache = NULL;
1656
1657 static volume_info_data *
1658 lookup_volume_info (char * root_dir)
1659 {
1660 volume_info_data * info;
1661
1662 for (info = volume_cache; info; info = info->next)
1663 if (xstrcasecmp (info->root_dir, root_dir) == 0)
1664 break;
1665 return info;
1666 }
1667
1668 static void
1669 add_volume_info (char * root_dir, volume_info_data * info)
1670 {
1671 info->root_dir = xstrdup (root_dir);
1672 info->next = volume_cache;
1673 volume_cache = info;
1674 }
1675
1676
1677 /* Wrapper for GetVolumeInformation, which uses caching to avoid
1678 performance penalty (~2ms on 486 for local drives, 7.5ms for local
1679 cdrom drive, ~5-10ms or more for remote drives on LAN). */
1680 volume_info_data *
1681 GetCachedVolumeInformation (char * root_dir)
1682 {
1683 volume_info_data * info;
1684 char default_root[ MAX_PATH ];
1685
1686 /* NULL for root_dir means use root from current directory. */
1687 if (root_dir == NULL)
1688 {
1689 if (GetCurrentDirectory (MAX_PATH, default_root) == 0)
1690 return NULL;
1691 parse_root (default_root, &root_dir);
1692 *root_dir = 0;
1693 root_dir = default_root;
1694 }
1695
1696 /* Local fixed drives can be cached permanently. Removable drives
1697 cannot be cached permanently, since the volume name and serial
1698 number (if nothing else) can change. Remote drives should be
1699 treated as if they are removable, since there is no sure way to
1700 tell whether they are or not. Also, the UNC association of drive
1701 letters mapped to remote volumes can be changed at any time (even
1702 by other processes) without notice.
1703
1704 As a compromise, so we can benefit from caching info for remote
1705 volumes, we use a simple expiry mechanism to invalidate cache
1706 entries that are more than ten seconds old. */
1707
1708 #if 0
1709 /* No point doing this, because WNetGetConnection is even slower than
1710 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
1711 GetDriveType is about the only call of this type which does not
1712 involve network access, and so is extremely quick). */
1713
1714 /* Map drive letter to UNC if remote. */
1715 if ( isalpha( root_dir[0] ) && !fixed[ DRIVE_INDEX( root_dir[0] ) ] )
1716 {
1717 char remote_name[ 256 ];
1718 char drive[3] = { root_dir[0], ':' };
1719
1720 if (WNetGetConnection (drive, remote_name, sizeof (remote_name))
1721 == NO_ERROR)
1722 /* do something */ ;
1723 }
1724 #endif
1725
1726 info = lookup_volume_info (root_dir);
1727
1728 if (info == NULL || ! VOLINFO_STILL_VALID (root_dir, info))
1729 {
1730 char name[ 256 ];
1731 DWORD serialnum;
1732 DWORD maxcomp;
1733 DWORD flags;
1734 char type[ 256 ];
1735
1736 /* Info is not cached, or is stale. */
1737 if (!GetVolumeInformation (root_dir,
1738 name, sizeof (name),
1739 &serialnum,
1740 &maxcomp,
1741 &flags,
1742 type, sizeof (type)))
1743 return NULL;
1744
1745 /* Cache the volume information for future use, overwriting existing
1746 entry if present. */
1747 if (info == NULL)
1748 {
1749 info = (volume_info_data *) xmalloc (sizeof (volume_info_data));
1750 add_volume_info (root_dir, info);
1751 }
1752 else
1753 {
1754 xfree (info->name);
1755 xfree (info->type);
1756 }
1757
1758 info->name = xstrdup (name);
1759 info->serialnum = serialnum;
1760 info->maxcomp = maxcomp;
1761 info->flags = flags;
1762 info->type = xstrdup (type);
1763 info->timestamp = GetTickCount ();
1764 }
1765
1766 return info;
1767 }
1768
1769 /* Get information on the volume where name is held; set path pointer to
1770 start of pathname in name (past UNC header\volume header if present). */
1771 int
1772 get_volume_info (const char * name, const char ** pPath)
1773 {
1774 char temp[MAX_PATH];
1775 char *rootname = NULL; /* default to current volume */
1776 volume_info_data * info;
1777
1778 if (name == NULL)
1779 return FALSE;
1780
1781 /* find the root name of the volume if given */
1782 if (isalpha (name[0]) && name[1] == ':')
1783 {
1784 rootname = temp;
1785 temp[0] = *name++;
1786 temp[1] = *name++;
1787 temp[2] = '\\';
1788 temp[3] = 0;
1789 }
1790 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
1791 {
1792 char *str = temp;
1793 int slashes = 4;
1794 rootname = temp;
1795 do
1796 {
1797 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
1798 break;
1799 *str++ = *name++;
1800 }
1801 while ( *name );
1802
1803 *str++ = '\\';
1804 *str = 0;
1805 }
1806
1807 if (pPath)
1808 *pPath = name;
1809
1810 info = GetCachedVolumeInformation (rootname);
1811 if (info != NULL)
1812 {
1813 /* Set global referenced by other functions. */
1814 volume_info = *info;
1815 return TRUE;
1816 }
1817 return FALSE;
1818 }
1819
1820 /* Determine if volume is FAT format (ie. only supports short 8.3
1821 names); also set path pointer to start of pathname in name. */
1822 int
1823 is_fat_volume (const char * name, const char ** pPath)
1824 {
1825 if (get_volume_info (name, pPath))
1826 return (volume_info.maxcomp == 12);
1827 return FALSE;
1828 }
1829
1830 /* Map filename to a valid 8.3 name if necessary. */
1831 const char *
1832 map_w32_filename (const char * name, const char ** pPath)
1833 {
1834 static char shortname[MAX_PATH];
1835 char * str = shortname;
1836 char c;
1837 char * path;
1838 const char * save_name = name;
1839
1840 if (strlen (name) >= MAX_PATH)
1841 {
1842 /* Return a filename which will cause callers to fail. */
1843 strcpy (shortname, "?");
1844 return shortname;
1845 }
1846
1847 if (is_fat_volume (name, (const char **)&path)) /* truncate to 8.3 */
1848 {
1849 register int left = 8; /* maximum number of chars in part */
1850 register int extn = 0; /* extension added? */
1851 register int dots = 2; /* maximum number of dots allowed */
1852
1853 while (name < path)
1854 *str++ = *name++; /* skip past UNC header */
1855
1856 while ((c = *name++))
1857 {
1858 switch ( c )
1859 {
1860 case '\\':
1861 case '/':
1862 *str++ = '\\';
1863 extn = 0; /* reset extension flags */
1864 dots = 2; /* max 2 dots */
1865 left = 8; /* max length 8 for main part */
1866 break;
1867 case ':':
1868 *str++ = ':';
1869 extn = 0; /* reset extension flags */
1870 dots = 2; /* max 2 dots */
1871 left = 8; /* max length 8 for main part */
1872 break;
1873 case '.':
1874 if ( dots )
1875 {
1876 /* Convert path components of the form .xxx to _xxx,
1877 but leave . and .. as they are. This allows .emacs
1878 to be read as _emacs, for example. */
1879
1880 if (! *name ||
1881 *name == '.' ||
1882 IS_DIRECTORY_SEP (*name))
1883 {
1884 *str++ = '.';
1885 dots--;
1886 }
1887 else
1888 {
1889 *str++ = '_';
1890 left--;
1891 dots = 0;
1892 }
1893 }
1894 else if ( !extn )
1895 {
1896 *str++ = '.';
1897 extn = 1; /* we've got an extension */
1898 left = 3; /* 3 chars in extension */
1899 }
1900 else
1901 {
1902 /* any embedded dots after the first are converted to _ */
1903 *str++ = '_';
1904 }
1905 break;
1906 case '~':
1907 case '#': /* don't lose these, they're important */
1908 if ( ! left )
1909 str[-1] = c; /* replace last character of part */
1910 /* FALLTHRU */
1911 default:
1912 if ( left )
1913 {
1914 *str++ = tolower (c); /* map to lower case (looks nicer) */
1915 left--;
1916 dots = 0; /* started a path component */
1917 }
1918 break;
1919 }
1920 }
1921 *str = '\0';
1922 }
1923 else
1924 {
1925 strcpy (shortname, name);
1926 unixtodos_filename (shortname);
1927 }
1928
1929 if (pPath)
1930 *pPath = shortname + (path - save_name);
1931
1932 return shortname;
1933 }
1934
1935 static int
1936 is_exec (const char * name)
1937 {
1938 char * p = strrchr (name, '.');
1939 return
1940 (p != NULL
1941 && (xstrcasecmp (p, ".exe") == 0 ||
1942 xstrcasecmp (p, ".com") == 0 ||
1943 xstrcasecmp (p, ".bat") == 0 ||
1944 xstrcasecmp (p, ".cmd") == 0));
1945 }
1946
1947 /* Emulate the Unix directory procedures opendir, closedir,
1948 and readdir. We can't use the procedures supplied in sysdep.c,
1949 so we provide them here. */
1950
1951 struct direct dir_static; /* simulated directory contents */
1952 static HANDLE dir_find_handle = INVALID_HANDLE_VALUE;
1953 static int dir_is_fat;
1954 static char dir_pathname[MAXPATHLEN+1];
1955 static WIN32_FIND_DATA dir_find_data;
1956
1957 /* Support shares on a network resource as subdirectories of a read-only
1958 root directory. */
1959 static HANDLE wnet_enum_handle = INVALID_HANDLE_VALUE;
1960 HANDLE open_unc_volume (const char *);
1961 char *read_unc_volume (HANDLE, char *, int);
1962 void close_unc_volume (HANDLE);
1963
1964 DIR *
1965 opendir (char *filename)
1966 {
1967 DIR *dirp;
1968
1969 /* Opening is done by FindFirstFile. However, a read is inherent to
1970 this operation, so we defer the open until read time. */
1971
1972 if (dir_find_handle != INVALID_HANDLE_VALUE)
1973 return NULL;
1974 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
1975 return NULL;
1976
1977 if (is_unc_volume (filename))
1978 {
1979 wnet_enum_handle = open_unc_volume (filename);
1980 if (wnet_enum_handle == INVALID_HANDLE_VALUE)
1981 return NULL;
1982 }
1983
1984 if (!(dirp = (DIR *) malloc (sizeof (DIR))))
1985 return NULL;
1986
1987 dirp->dd_fd = 0;
1988 dirp->dd_loc = 0;
1989 dirp->dd_size = 0;
1990
1991 strncpy (dir_pathname, map_w32_filename (filename, NULL), MAXPATHLEN);
1992 dir_pathname[MAXPATHLEN] = '\0';
1993 dir_is_fat = is_fat_volume (filename, NULL);
1994
1995 return dirp;
1996 }
1997
1998 void
1999 closedir (DIR *dirp)
2000 {
2001 /* If we have a find-handle open, close it. */
2002 if (dir_find_handle != INVALID_HANDLE_VALUE)
2003 {
2004 FindClose (dir_find_handle);
2005 dir_find_handle = INVALID_HANDLE_VALUE;
2006 }
2007 else if (wnet_enum_handle != INVALID_HANDLE_VALUE)
2008 {
2009 close_unc_volume (wnet_enum_handle);
2010 wnet_enum_handle = INVALID_HANDLE_VALUE;
2011 }
2012 xfree ((char *) dirp);
2013 }
2014
2015 struct direct *
2016 readdir (DIR *dirp)
2017 {
2018 int downcase = !NILP (Vw32_downcase_file_names);
2019
2020 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
2021 {
2022 if (!read_unc_volume (wnet_enum_handle,
2023 dir_find_data.cFileName,
2024 MAX_PATH))
2025 return NULL;
2026 }
2027 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
2028 else if (dir_find_handle == INVALID_HANDLE_VALUE)
2029 {
2030 char filename[MAXNAMLEN + 3];
2031 int ln;
2032
2033 strcpy (filename, dir_pathname);
2034 ln = strlen (filename) - 1;
2035 if (!IS_DIRECTORY_SEP (filename[ln]))
2036 strcat (filename, "\\");
2037 strcat (filename, "*");
2038
2039 dir_find_handle = FindFirstFile (filename, &dir_find_data);
2040
2041 if (dir_find_handle == INVALID_HANDLE_VALUE)
2042 return NULL;
2043 }
2044 else
2045 {
2046 if (!FindNextFile (dir_find_handle, &dir_find_data))
2047 return NULL;
2048 }
2049
2050 /* Emacs never uses this value, so don't bother making it match
2051 value returned by stat(). */
2052 dir_static.d_ino = 1;
2053
2054 strcpy (dir_static.d_name, dir_find_data.cFileName);
2055
2056 /* If the file name in cFileName[] includes `?' characters, it means
2057 the original file name used characters that cannot be represented
2058 by the current ANSI codepage. To avoid total lossage, retrieve
2059 the short 8+3 alias of the long file name. */
2060 if (_mbspbrk (dir_static.d_name, "?"))
2061 {
2062 strcpy (dir_static.d_name, dir_find_data.cAlternateFileName);
2063 downcase = 1; /* 8+3 aliases are returned in all caps */
2064 }
2065 dir_static.d_namlen = strlen (dir_static.d_name);
2066 dir_static.d_reclen = sizeof (struct direct) - MAXNAMLEN + 3 +
2067 dir_static.d_namlen - dir_static.d_namlen % 4;
2068
2069 /* If the file name in cFileName[] includes `?' characters, it means
2070 the original file name used characters that cannot be represented
2071 by the current ANSI codepage. To avoid total lossage, retrieve
2072 the short 8+3 alias of the long file name. */
2073 if (_mbspbrk (dir_find_data.cFileName, "?"))
2074 {
2075 strcpy (dir_static.d_name, dir_find_data.cAlternateFileName);
2076 /* 8+3 aliases are returned in all caps, which could break
2077 various alists that look at filenames' extensions. */
2078 downcase = 1;
2079 }
2080 else
2081 strcpy (dir_static.d_name, dir_find_data.cFileName);
2082 dir_static.d_namlen = strlen (dir_static.d_name);
2083 if (dir_is_fat)
2084 _strlwr (dir_static.d_name);
2085 else if (downcase)
2086 {
2087 register char *p;
2088 for (p = dir_static.d_name; *p; p++)
2089 if (*p >= 'a' && *p <= 'z')
2090 break;
2091 if (!*p)
2092 _strlwr (dir_static.d_name);
2093 }
2094
2095 return &dir_static;
2096 }
2097
2098 HANDLE
2099 open_unc_volume (const char *path)
2100 {
2101 NETRESOURCE nr;
2102 HANDLE henum;
2103 int result;
2104
2105 nr.dwScope = RESOURCE_GLOBALNET;
2106 nr.dwType = RESOURCETYPE_DISK;
2107 nr.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
2108 nr.dwUsage = RESOURCEUSAGE_CONTAINER;
2109 nr.lpLocalName = NULL;
2110 nr.lpRemoteName = (LPSTR)map_w32_filename (path, NULL);
2111 nr.lpComment = NULL;
2112 nr.lpProvider = NULL;
2113
2114 result = WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
2115 RESOURCEUSAGE_CONNECTABLE, &nr, &henum);
2116
2117 if (result == NO_ERROR)
2118 return henum;
2119 else
2120 return INVALID_HANDLE_VALUE;
2121 }
2122
2123 char *
2124 read_unc_volume (HANDLE henum, char *readbuf, int size)
2125 {
2126 DWORD count;
2127 int result;
2128 DWORD bufsize = 512;
2129 char *buffer;
2130 char *ptr;
2131
2132 count = 1;
2133 buffer = alloca (bufsize);
2134 result = WNetEnumResource (wnet_enum_handle, &count, buffer, &bufsize);
2135 if (result != NO_ERROR)
2136 return NULL;
2137
2138 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
2139 ptr = ((LPNETRESOURCE) buffer)->lpRemoteName;
2140 ptr += 2;
2141 while (*ptr && !IS_DIRECTORY_SEP (*ptr)) ptr++;
2142 ptr++;
2143
2144 strncpy (readbuf, ptr, size);
2145 return readbuf;
2146 }
2147
2148 void
2149 close_unc_volume (HANDLE henum)
2150 {
2151 if (henum != INVALID_HANDLE_VALUE)
2152 WNetCloseEnum (henum);
2153 }
2154
2155 DWORD
2156 unc_volume_file_attributes (const char *path)
2157 {
2158 HANDLE henum;
2159 DWORD attrs;
2160
2161 henum = open_unc_volume (path);
2162 if (henum == INVALID_HANDLE_VALUE)
2163 return -1;
2164
2165 attrs = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY;
2166
2167 close_unc_volume (henum);
2168
2169 return attrs;
2170 }
2171
2172 /* Ensure a network connection is authenticated. */
2173 static void
2174 logon_network_drive (const char *path)
2175 {
2176 NETRESOURCE resource;
2177 char share[MAX_PATH];
2178 int i, n_slashes;
2179 char drive[4];
2180
2181 sprintf (drive, "%c:\\", path[0]);
2182
2183 /* Only logon to networked drives. */
2184 if ((!IS_DIRECTORY_SEP (path[0]) || !IS_DIRECTORY_SEP (path[1]))
2185 && GetDriveType (drive) != DRIVE_REMOTE)
2186 return;
2187
2188 n_slashes = 2;
2189 strncpy (share, path, MAX_PATH);
2190 /* Truncate to just server and share name. */
2191 for (i = 2; i < MAX_PATH; i++)
2192 {
2193 if (IS_DIRECTORY_SEP (share[i]) && ++n_slashes > 3)
2194 {
2195 share[i] = '\0';
2196 break;
2197 }
2198 }
2199
2200 resource.dwType = RESOURCETYPE_DISK;
2201 resource.lpLocalName = NULL;
2202 resource.lpRemoteName = share;
2203 resource.lpProvider = NULL;
2204
2205 WNetAddConnection2 (&resource, NULL, NULL, CONNECT_INTERACTIVE);
2206 }
2207
2208 /* Shadow some MSVC runtime functions to map requests for long filenames
2209 to reasonable short names if necessary. This was originally added to
2210 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
2211 long file names. */
2212
2213 int
2214 sys_access (const char * path, int mode)
2215 {
2216 DWORD attributes;
2217
2218 /* MSVC implementation doesn't recognize D_OK. */
2219 path = map_w32_filename (path, NULL);
2220 if (is_unc_volume (path))
2221 {
2222 attributes = unc_volume_file_attributes (path);
2223 if (attributes == -1) {
2224 errno = EACCES;
2225 return -1;
2226 }
2227 }
2228 else if ((attributes = GetFileAttributes (path)) == -1)
2229 {
2230 /* Should try mapping GetLastError to errno; for now just indicate
2231 that path doesn't exist. */
2232 errno = EACCES;
2233 return -1;
2234 }
2235 if ((mode & X_OK) != 0 && !is_exec (path))
2236 {
2237 errno = EACCES;
2238 return -1;
2239 }
2240 if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0)
2241 {
2242 errno = EACCES;
2243 return -1;
2244 }
2245 if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
2246 {
2247 errno = EACCES;
2248 return -1;
2249 }
2250 return 0;
2251 }
2252
2253 int
2254 sys_chdir (const char * path)
2255 {
2256 return _chdir (map_w32_filename (path, NULL));
2257 }
2258
2259 int
2260 sys_chmod (const char * path, int mode)
2261 {
2262 return _chmod (map_w32_filename (path, NULL), mode);
2263 }
2264
2265 int
2266 sys_chown (const char *path, uid_t owner, gid_t group)
2267 {
2268 if (sys_chmod (path, S_IREAD) == -1) /* check if file exists */
2269 return -1;
2270 return 0;
2271 }
2272
2273 int
2274 sys_creat (const char * path, int mode)
2275 {
2276 return _creat (map_w32_filename (path, NULL), mode);
2277 }
2278
2279 FILE *
2280 sys_fopen(const char * path, const char * mode)
2281 {
2282 int fd;
2283 int oflag;
2284 const char * mode_save = mode;
2285
2286 /* Force all file handles to be non-inheritable. This is necessary to
2287 ensure child processes don't unwittingly inherit handles that might
2288 prevent future file access. */
2289
2290 if (mode[0] == 'r')
2291 oflag = O_RDONLY;
2292 else if (mode[0] == 'w' || mode[0] == 'a')
2293 oflag = O_WRONLY | O_CREAT | O_TRUNC;
2294 else
2295 return NULL;
2296
2297 /* Only do simplistic option parsing. */
2298 while (*++mode)
2299 if (mode[0] == '+')
2300 {
2301 oflag &= ~(O_RDONLY | O_WRONLY);
2302 oflag |= O_RDWR;
2303 }
2304 else if (mode[0] == 'b')
2305 {
2306 oflag &= ~O_TEXT;
2307 oflag |= O_BINARY;
2308 }
2309 else if (mode[0] == 't')
2310 {
2311 oflag &= ~O_BINARY;
2312 oflag |= O_TEXT;
2313 }
2314 else break;
2315
2316 fd = _open (map_w32_filename (path, NULL), oflag | _O_NOINHERIT, 0644);
2317 if (fd < 0)
2318 return NULL;
2319
2320 return _fdopen (fd, mode_save);
2321 }
2322
2323 /* This only works on NTFS volumes, but is useful to have. */
2324 int
2325 sys_link (const char * old, const char * new)
2326 {
2327 HANDLE fileh;
2328 int result = -1;
2329 char oldname[MAX_PATH], newname[MAX_PATH];
2330
2331 if (old == NULL || new == NULL)
2332 {
2333 errno = ENOENT;
2334 return -1;
2335 }
2336
2337 strcpy (oldname, map_w32_filename (old, NULL));
2338 strcpy (newname, map_w32_filename (new, NULL));
2339
2340 fileh = CreateFile (oldname, 0, 0, NULL, OPEN_EXISTING,
2341 FILE_FLAG_BACKUP_SEMANTICS, NULL);
2342 if (fileh != INVALID_HANDLE_VALUE)
2343 {
2344 int wlen;
2345
2346 /* Confusingly, the "alternate" stream name field does not apply
2347 when restoring a hard link, and instead contains the actual
2348 stream data for the link (ie. the name of the link to create).
2349 The WIN32_STREAM_ID structure before the cStreamName field is
2350 the stream header, which is then immediately followed by the
2351 stream data. */
2352
2353 struct {
2354 WIN32_STREAM_ID wid;
2355 WCHAR wbuffer[MAX_PATH]; /* extra space for link name */
2356 } data;
2357
2358 wlen = MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, newname, -1,
2359 data.wid.cStreamName, MAX_PATH);
2360 if (wlen > 0)
2361 {
2362 LPVOID context = NULL;
2363 DWORD wbytes = 0;
2364
2365 data.wid.dwStreamId = BACKUP_LINK;
2366 data.wid.dwStreamAttributes = 0;
2367 data.wid.Size.LowPart = wlen * sizeof(WCHAR);
2368 data.wid.Size.HighPart = 0;
2369 data.wid.dwStreamNameSize = 0;
2370
2371 if (BackupWrite (fileh, (LPBYTE)&data,
2372 offsetof (WIN32_STREAM_ID, cStreamName)
2373 + data.wid.Size.LowPart,
2374 &wbytes, FALSE, FALSE, &context)
2375 && BackupWrite (fileh, NULL, 0, &wbytes, TRUE, FALSE, &context))
2376 {
2377 /* succeeded */
2378 result = 0;
2379 }
2380 else
2381 {
2382 /* Should try mapping GetLastError to errno; for now just
2383 indicate a general error (eg. links not supported). */
2384 errno = EINVAL; // perhaps EMLINK?
2385 }
2386 }
2387
2388 CloseHandle (fileh);
2389 }
2390 else
2391 errno = ENOENT;
2392
2393 return result;
2394 }
2395
2396 int
2397 sys_mkdir (const char * path)
2398 {
2399 return _mkdir (map_w32_filename (path, NULL));
2400 }
2401
2402 /* Because of long name mapping issues, we need to implement this
2403 ourselves. Also, MSVC's _mktemp returns NULL when it can't generate
2404 a unique name, instead of setting the input template to an empty
2405 string.
2406
2407 Standard algorithm seems to be use pid or tid with a letter on the
2408 front (in place of the 6 X's) and cycle through the letters to find a
2409 unique name. We extend that to allow any reasonable character as the
2410 first of the 6 X's. */
2411 char *
2412 sys_mktemp (char * template)
2413 {
2414 char * p;
2415 int i;
2416 unsigned uid = GetCurrentThreadId ();
2417 static char first_char[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
2418
2419 if (template == NULL)
2420 return NULL;
2421 p = template + strlen (template);
2422 i = 5;
2423 /* replace up to the last 5 X's with uid in decimal */
2424 while (--p >= template && p[0] == 'X' && --i >= 0)
2425 {
2426 p[0] = '0' + uid % 10;
2427 uid /= 10;
2428 }
2429
2430 if (i < 0 && p[0] == 'X')
2431 {
2432 i = 0;
2433 do
2434 {
2435 int save_errno = errno;
2436 p[0] = first_char[i];
2437 if (sys_access (template, 0) < 0)
2438 {
2439 errno = save_errno;
2440 return template;
2441 }
2442 }
2443 while (++i < sizeof (first_char));
2444 }
2445
2446 /* Template is badly formed or else we can't generate a unique name,
2447 so return empty string */
2448 template[0] = 0;
2449 return template;
2450 }
2451
2452 int
2453 sys_open (const char * path, int oflag, int mode)
2454 {
2455 const char* mpath = map_w32_filename (path, NULL);
2456 /* Try to open file without _O_CREAT, to be able to write to hidden
2457 and system files. Force all file handles to be
2458 non-inheritable. */
2459 int res = _open (mpath, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
2460 if (res >= 0)
2461 return res;
2462 return _open (mpath, oflag | _O_NOINHERIT, mode);
2463 }
2464
2465 int
2466 sys_rename (const char * oldname, const char * newname)
2467 {
2468 BOOL result;
2469 char temp[MAX_PATH];
2470
2471 /* MoveFile on Windows 95 doesn't correctly change the short file name
2472 alias in a number of circumstances (it is not easy to predict when
2473 just by looking at oldname and newname, unfortunately). In these
2474 cases, renaming through a temporary name avoids the problem.
2475
2476 A second problem on Windows 95 is that renaming through a temp name when
2477 newname is uppercase fails (the final long name ends up in
2478 lowercase, although the short alias might be uppercase) UNLESS the
2479 long temp name is not 8.3.
2480
2481 So, on Windows 95 we always rename through a temp name, and we make sure
2482 the temp name has a long extension to ensure correct renaming. */
2483
2484 strcpy (temp, map_w32_filename (oldname, NULL));
2485
2486 if (os_subtype == OS_WIN95)
2487 {
2488 char * o;
2489 char * p;
2490 int i = 0;
2491
2492 oldname = map_w32_filename (oldname, NULL);
2493 if (o = strrchr (oldname, '\\'))
2494 o++;
2495 else
2496 o = (char *) oldname;
2497
2498 if (p = strrchr (temp, '\\'))
2499 p++;
2500 else
2501 p = temp;
2502
2503 do
2504 {
2505 /* Force temp name to require a manufactured 8.3 alias - this
2506 seems to make the second rename work properly. */
2507 sprintf (p, "_.%s.%u", o, i);
2508 i++;
2509 result = rename (oldname, temp);
2510 }
2511 /* This loop must surely terminate! */
2512 while (result < 0 && errno == EEXIST);
2513 if (result < 0)
2514 return -1;
2515 }
2516
2517 /* Emulate Unix behaviour - newname is deleted if it already exists
2518 (at least if it is a file; don't do this for directories).
2519
2520 Since we mustn't do this if we are just changing the case of the
2521 file name (we would end up deleting the file we are trying to
2522 rename!), we let rename detect if the destination file already
2523 exists - that way we avoid the possible pitfalls of trying to
2524 determine ourselves whether two names really refer to the same
2525 file, which is not always possible in the general case. (Consider
2526 all the permutations of shared or subst'd drives, etc.) */
2527
2528 newname = map_w32_filename (newname, NULL);
2529 result = rename (temp, newname);
2530
2531 if (result < 0
2532 && errno == EEXIST
2533 && _chmod (newname, 0666) == 0
2534 && _unlink (newname) == 0)
2535 result = rename (temp, newname);
2536
2537 return result;
2538 }
2539
2540 int
2541 sys_rmdir (const char * path)
2542 {
2543 return _rmdir (map_w32_filename (path, NULL));
2544 }
2545
2546 int
2547 sys_unlink (const char * path)
2548 {
2549 path = map_w32_filename (path, NULL);
2550
2551 /* On Unix, unlink works without write permission. */
2552 _chmod (path, 0666);
2553 return _unlink (path);
2554 }
2555
2556 static FILETIME utc_base_ft;
2557 static long double utc_base;
2558 static int init = 0;
2559
2560 static time_t
2561 convert_time (FILETIME ft)
2562 {
2563 long double ret;
2564
2565 if (!init)
2566 {
2567 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
2568 SYSTEMTIME st;
2569
2570 st.wYear = 1970;
2571 st.wMonth = 1;
2572 st.wDay = 1;
2573 st.wHour = 0;
2574 st.wMinute = 0;
2575 st.wSecond = 0;
2576 st.wMilliseconds = 0;
2577
2578 SystemTimeToFileTime (&st, &utc_base_ft);
2579 utc_base = (long double) utc_base_ft.dwHighDateTime
2580 * 4096.0L * 1024.0L * 1024.0L + utc_base_ft.dwLowDateTime;
2581 init = 1;
2582 }
2583
2584 if (CompareFileTime (&ft, &utc_base_ft) < 0)
2585 return 0;
2586
2587 ret = (long double) ft.dwHighDateTime
2588 * 4096.0L * 1024.0L * 1024.0L + ft.dwLowDateTime;
2589 ret -= utc_base;
2590 return (time_t) (ret * 1e-7L);
2591 }
2592
2593 void
2594 convert_from_time_t (time_t time, FILETIME * pft)
2595 {
2596 long double tmp;
2597
2598 if (!init)
2599 {
2600 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
2601 SYSTEMTIME st;
2602
2603 st.wYear = 1970;
2604 st.wMonth = 1;
2605 st.wDay = 1;
2606 st.wHour = 0;
2607 st.wMinute = 0;
2608 st.wSecond = 0;
2609 st.wMilliseconds = 0;
2610
2611 SystemTimeToFileTime (&st, &utc_base_ft);
2612 utc_base = (long double) utc_base_ft.dwHighDateTime
2613 * 4096 * 1024 * 1024 + utc_base_ft.dwLowDateTime;
2614 init = 1;
2615 }
2616
2617 /* time in 100ns units since 1-Jan-1601 */
2618 tmp = (long double) time * 1e7 + utc_base;
2619 pft->dwHighDateTime = (DWORD) (tmp / (4096.0 * 1024 * 1024));
2620 pft->dwLowDateTime = (DWORD) (tmp - (4096.0 * 1024 * 1024) * pft->dwHighDateTime);
2621 }
2622
2623 #if 0
2624 /* No reason to keep this; faking inode values either by hashing or even
2625 using the file index from GetInformationByHandle, is not perfect and
2626 so by default Emacs doesn't use the inode values on Windows.
2627 Instead, we now determine file-truename correctly (except for
2628 possible drive aliasing etc). */
2629
2630 /* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
2631 static unsigned
2632 hashval (const unsigned char * str)
2633 {
2634 unsigned h = 0;
2635 while (*str)
2636 {
2637 h = (h << 4) + *str++;
2638 h ^= (h >> 28);
2639 }
2640 return h;
2641 }
2642
2643 /* Return the hash value of the canonical pathname, excluding the
2644 drive/UNC header, to get a hopefully unique inode number. */
2645 static DWORD
2646 generate_inode_val (const char * name)
2647 {
2648 char fullname[ MAX_PATH ];
2649 char * p;
2650 unsigned hash;
2651
2652 /* Get the truly canonical filename, if it exists. (Note: this
2653 doesn't resolve aliasing due to subst commands, or recognise hard
2654 links. */
2655 if (!w32_get_long_filename ((char *)name, fullname, MAX_PATH))
2656 abort ();
2657
2658 parse_root (fullname, &p);
2659 /* Normal W32 filesystems are still case insensitive. */
2660 _strlwr (p);
2661 return hashval (p);
2662 }
2663
2664 #endif
2665
2666 static PSECURITY_DESCRIPTOR
2667 get_file_security_desc (const char *fname)
2668 {
2669 PSECURITY_DESCRIPTOR psd = NULL;
2670 DWORD sd_len, err;
2671 SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION
2672 | GROUP_SECURITY_INFORMATION /* | DACL_SECURITY_INFORMATION */ ;
2673
2674 if (!get_file_security (fname, si, psd, 0, &sd_len))
2675 {
2676 err = GetLastError ();
2677 if (err != ERROR_INSUFFICIENT_BUFFER)
2678 return NULL;
2679 }
2680
2681 psd = xmalloc (sd_len);
2682 if (!get_file_security (fname, si, psd, sd_len, &sd_len))
2683 {
2684 xfree (psd);
2685 return NULL;
2686 }
2687
2688 return psd;
2689 }
2690
2691 static DWORD
2692 get_rid (PSID sid)
2693 {
2694 unsigned n_subauthorities;
2695
2696 /* Use the last sub-authority value of the RID, the relative
2697 portion of the SID, as user/group ID. */
2698 n_subauthorities = *get_sid_sub_authority_count (sid);
2699 if (n_subauthorities < 1)
2700 return 0; /* the "World" RID */
2701 return *get_sid_sub_authority (sid, n_subauthorities - 1);
2702 }
2703
2704 #define UID 1
2705 #define GID 2
2706
2707 static int
2708 get_name_and_id (PSECURITY_DESCRIPTOR psd, const char *fname,
2709 int *id, char *nm, int what)
2710 {
2711 PSID sid = NULL;
2712 char machine[MAX_COMPUTERNAME_LENGTH+1];
2713 BOOL dflt;
2714 SID_NAME_USE ignore;
2715 char name[UNLEN+1];
2716 DWORD name_len = sizeof (name);
2717 char domain[1024];
2718 DWORD domain_len = sizeof(domain);
2719 char *mp = NULL;
2720 int use_dflt = 0;
2721 int result;
2722
2723 if (what == UID)
2724 result = get_security_descriptor_owner (psd, &sid, &dflt);
2725 else if (what == GID)
2726 result = get_security_descriptor_group (psd, &sid, &dflt);
2727 else
2728 result = 0;
2729
2730 if (!result || !is_valid_sid (sid))
2731 use_dflt = 1;
2732 else
2733 {
2734 /* If FNAME is a UNC, we need to lookup account on the
2735 specified machine. */
2736 if (IS_DIRECTORY_SEP (fname[0]) && IS_DIRECTORY_SEP (fname[1])
2737 && fname[2] != '\0')
2738 {
2739 const char *s;
2740 char *p;
2741
2742 for (s = fname + 2, p = machine;
2743 *s && !IS_DIRECTORY_SEP (*s); s++, p++)
2744 *p = *s;
2745 *p = '\0';
2746 mp = machine;
2747 }
2748
2749 if (!lookup_account_sid (mp, sid, name, &name_len,
2750 domain, &domain_len, &ignore)
2751 || name_len > UNLEN+1)
2752 use_dflt = 1;
2753 else
2754 {
2755 *id = get_rid (sid);
2756 strcpy (nm, name);
2757 }
2758 }
2759 return use_dflt;
2760 }
2761
2762 static void
2763 get_file_owner_and_group (
2764 PSECURITY_DESCRIPTOR psd,
2765 const char *fname,
2766 struct stat *st)
2767 {
2768 int dflt_usr = 0, dflt_grp = 0;
2769
2770 if (!psd)
2771 {
2772 dflt_usr = 1;
2773 dflt_grp = 1;
2774 }
2775 else
2776 {
2777 if (get_name_and_id (psd, fname, &st->st_uid, st->st_uname, UID))
2778 dflt_usr = 1;
2779 if (get_name_and_id (psd, fname, &st->st_gid, st->st_gname, GID))
2780 dflt_grp = 1;
2781 }
2782 /* Consider files to belong to current user/group, if we cannot get
2783 more accurate information. */
2784 if (dflt_usr)
2785 {
2786 st->st_uid = dflt_passwd.pw_uid;
2787 strcpy (st->st_uname, dflt_passwd.pw_name);
2788 }
2789 if (dflt_grp)
2790 {
2791 st->st_gid = dflt_passwd.pw_gid;
2792 strcpy (st->st_gname, dflt_group.gr_name);
2793 }
2794 }
2795
2796 /* MSVC stat function can't cope with UNC names and has other bugs, so
2797 replace it with our own. This also allows us to calculate consistent
2798 inode values without hacks in the main Emacs code. */
2799 int
2800 stat (const char * path, struct stat * buf)
2801 {
2802 char *name, *r;
2803 WIN32_FIND_DATA wfd;
2804 HANDLE fh;
2805 unsigned __int64 fake_inode;
2806 int permission;
2807 int len;
2808 int rootdir = FALSE;
2809 PSECURITY_DESCRIPTOR psd = NULL;
2810
2811 if (path == NULL || buf == NULL)
2812 {
2813 errno = EFAULT;
2814 return -1;
2815 }
2816
2817 name = (char *) map_w32_filename (path, &path);
2818 /* Must be valid filename, no wild cards or other invalid
2819 characters. We use _mbspbrk to support multibyte strings that
2820 might look to strpbrk as if they included literal *, ?, and other
2821 characters mentioned below that are disallowed by Windows
2822 filesystems. */
2823 if (_mbspbrk (name, "*?|<>\""))
2824 {
2825 errno = ENOENT;
2826 return -1;
2827 }
2828
2829 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
2830 r = IS_DEVICE_SEP (name[1]) ? &name[2] : name;
2831 if (IS_DIRECTORY_SEP (r[0]) && r[1] == '.' && r[2] == '.' && r[3] == '\0')
2832 {
2833 r[1] = r[2] = '\0';
2834 }
2835
2836 /* Remove trailing directory separator, unless name is the root
2837 directory of a drive or UNC volume in which case ensure there
2838 is a trailing separator. */
2839 len = strlen (name);
2840 rootdir = (path >= name + len - 1
2841 && (IS_DIRECTORY_SEP (*path) || *path == 0));
2842 name = strcpy (alloca (len + 2), name);
2843
2844 if (is_unc_volume (name))
2845 {
2846 DWORD attrs = unc_volume_file_attributes (name);
2847
2848 if (attrs == -1)
2849 return -1;
2850
2851 memset (&wfd, 0, sizeof (wfd));
2852 wfd.dwFileAttributes = attrs;
2853 wfd.ftCreationTime = utc_base_ft;
2854 wfd.ftLastAccessTime = utc_base_ft;
2855 wfd.ftLastWriteTime = utc_base_ft;
2856 strcpy (wfd.cFileName, name);
2857 }
2858 else if (rootdir)
2859 {
2860 if (!IS_DIRECTORY_SEP (name[len-1]))
2861 strcat (name, "\\");
2862 if (GetDriveType (name) < 2)
2863 {
2864 errno = ENOENT;
2865 return -1;
2866 }
2867 memset (&wfd, 0, sizeof (wfd));
2868 wfd.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
2869 wfd.ftCreationTime = utc_base_ft;
2870 wfd.ftLastAccessTime = utc_base_ft;
2871 wfd.ftLastWriteTime = utc_base_ft;
2872 strcpy (wfd.cFileName, name);
2873 }
2874 else
2875 {
2876 if (IS_DIRECTORY_SEP (name[len-1]))
2877 name[len - 1] = 0;
2878
2879 /* (This is hacky, but helps when doing file completions on
2880 network drives.) Optimize by using information available from
2881 active readdir if possible. */
2882 len = strlen (dir_pathname);
2883 if (IS_DIRECTORY_SEP (dir_pathname[len-1]))
2884 len--;
2885 if (dir_find_handle != INVALID_HANDLE_VALUE
2886 && strnicmp (name, dir_pathname, len) == 0
2887 && IS_DIRECTORY_SEP (name[len])
2888 && xstrcasecmp (name + len + 1, dir_static.d_name) == 0)
2889 {
2890 /* This was the last entry returned by readdir. */
2891 wfd = dir_find_data;
2892 }
2893 else
2894 {
2895 logon_network_drive (name);
2896
2897 fh = FindFirstFile (name, &wfd);
2898 if (fh == INVALID_HANDLE_VALUE)
2899 {
2900 errno = ENOENT;
2901 return -1;
2902 }
2903 FindClose (fh);
2904 }
2905 }
2906
2907 if (!(NILP (Vw32_get_true_file_attributes)
2908 || (EQ (Vw32_get_true_file_attributes, Qlocal) &&
2909 GetDriveType (name) != DRIVE_FIXED))
2910 /* No access rights required to get info. */
2911 && (fh = CreateFile (name, 0, 0, NULL, OPEN_EXISTING,
2912 FILE_FLAG_BACKUP_SEMANTICS, NULL))
2913 != INVALID_HANDLE_VALUE)
2914 {
2915 /* This is more accurate in terms of gettting the correct number
2916 of links, but is quite slow (it is noticeable when Emacs is
2917 making a list of file name completions). */
2918 BY_HANDLE_FILE_INFORMATION info;
2919
2920 if (GetFileInformationByHandle (fh, &info))
2921 {
2922 buf->st_nlink = info.nNumberOfLinks;
2923 /* Might as well use file index to fake inode values, but this
2924 is not guaranteed to be unique unless we keep a handle open
2925 all the time (even then there are situations where it is
2926 not unique). Reputedly, there are at most 48 bits of info
2927 (on NTFS, presumably less on FAT). */
2928 fake_inode = info.nFileIndexHigh;
2929 fake_inode <<= 32;
2930 fake_inode += info.nFileIndexLow;
2931 }
2932 else
2933 {
2934 buf->st_nlink = 1;
2935 fake_inode = 0;
2936 }
2937
2938 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
2939 {
2940 buf->st_mode = S_IFDIR;
2941 }
2942 else
2943 {
2944 switch (GetFileType (fh))
2945 {
2946 case FILE_TYPE_DISK:
2947 buf->st_mode = S_IFREG;
2948 break;
2949 case FILE_TYPE_PIPE:
2950 buf->st_mode = S_IFIFO;
2951 break;
2952 case FILE_TYPE_CHAR:
2953 case FILE_TYPE_UNKNOWN:
2954 default:
2955 buf->st_mode = S_IFCHR;
2956 }
2957 }
2958 CloseHandle (fh);
2959 psd = get_file_security_desc (name);
2960 get_file_owner_and_group (psd, name, buf);
2961 }
2962 else
2963 {
2964 /* Don't bother to make this information more accurate. */
2965 buf->st_mode = (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ?
2966 S_IFDIR : S_IFREG;
2967 buf->st_nlink = 1;
2968 fake_inode = 0;
2969
2970 get_file_owner_and_group (NULL, name, buf);
2971 }
2972 xfree (psd);
2973
2974 #if 0
2975 /* Not sure if there is any point in this. */
2976 if (!NILP (Vw32_generate_fake_inodes))
2977 fake_inode = generate_inode_val (name);
2978 else if (fake_inode == 0)
2979 {
2980 /* For want of something better, try to make everything unique. */
2981 static DWORD gen_num = 0;
2982 fake_inode = ++gen_num;
2983 }
2984 #endif
2985
2986 /* MSVC defines _ino_t to be short; other libc's might not. */
2987 if (sizeof (buf->st_ino) == 2)
2988 buf->st_ino = fake_inode ^ (fake_inode >> 16);
2989 else
2990 buf->st_ino = fake_inode;
2991
2992 /* volume_info is set indirectly by map_w32_filename */
2993 buf->st_dev = volume_info.serialnum;
2994 buf->st_rdev = volume_info.serialnum;
2995
2996
2997 buf->st_size = wfd.nFileSizeHigh;
2998 buf->st_size <<= 32;
2999 buf->st_size += wfd.nFileSizeLow;
3000
3001 /* Convert timestamps to Unix format. */
3002 buf->st_mtime = convert_time (wfd.ftLastWriteTime);
3003 buf->st_atime = convert_time (wfd.ftLastAccessTime);
3004 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
3005 buf->st_ctime = convert_time (wfd.ftCreationTime);
3006 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
3007
3008 /* determine rwx permissions */
3009 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
3010 permission = S_IREAD;
3011 else
3012 permission = S_IREAD | S_IWRITE;
3013
3014 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
3015 permission |= S_IEXEC;
3016 else if (is_exec (name))
3017 permission |= S_IEXEC;
3018
3019 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
3020
3021 return 0;
3022 }
3023
3024 /* Provide fstat and utime as well as stat for consistent handling of
3025 file timestamps. */
3026 int
3027 fstat (int desc, struct stat * buf)
3028 {
3029 HANDLE fh = (HANDLE) _get_osfhandle (desc);
3030 BY_HANDLE_FILE_INFORMATION info;
3031 unsigned __int64 fake_inode;
3032 int permission;
3033
3034 switch (GetFileType (fh) & ~FILE_TYPE_REMOTE)
3035 {
3036 case FILE_TYPE_DISK:
3037 buf->st_mode = S_IFREG;
3038 if (!GetFileInformationByHandle (fh, &info))
3039 {
3040 errno = EACCES;
3041 return -1;
3042 }
3043 break;
3044 case FILE_TYPE_PIPE:
3045 buf->st_mode = S_IFIFO;
3046 goto non_disk;
3047 case FILE_TYPE_CHAR:
3048 case FILE_TYPE_UNKNOWN:
3049 default:
3050 buf->st_mode = S_IFCHR;
3051 non_disk:
3052 memset (&info, 0, sizeof (info));
3053 info.dwFileAttributes = 0;
3054 info.ftCreationTime = utc_base_ft;
3055 info.ftLastAccessTime = utc_base_ft;
3056 info.ftLastWriteTime = utc_base_ft;
3057 }
3058
3059 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
3060 buf->st_mode = S_IFDIR;
3061
3062 buf->st_nlink = info.nNumberOfLinks;
3063 /* Might as well use file index to fake inode values, but this
3064 is not guaranteed to be unique unless we keep a handle open
3065 all the time (even then there are situations where it is
3066 not unique). Reputedly, there are at most 48 bits of info
3067 (on NTFS, presumably less on FAT). */
3068 fake_inode = info.nFileIndexHigh;
3069 fake_inode <<= 32;
3070 fake_inode += info.nFileIndexLow;
3071
3072 /* MSVC defines _ino_t to be short; other libc's might not. */
3073 if (sizeof (buf->st_ino) == 2)
3074 buf->st_ino = fake_inode ^ (fake_inode >> 16);
3075 else
3076 buf->st_ino = fake_inode;
3077
3078 /* Consider files to belong to current user.
3079 FIXME: this should use GetSecurityInfo API, but it is only
3080 available for _WIN32_WINNT >= 0x501. */
3081 buf->st_uid = dflt_passwd.pw_uid;
3082 buf->st_gid = dflt_passwd.pw_gid;
3083 strcpy (buf->st_uname, dflt_passwd.pw_name);
3084 strcpy (buf->st_gname, dflt_group.gr_name);
3085
3086 buf->st_dev = info.dwVolumeSerialNumber;
3087 buf->st_rdev = info.dwVolumeSerialNumber;
3088
3089 buf->st_size = info.nFileSizeHigh;
3090 buf->st_size <<= 32;
3091 buf->st_size += info.nFileSizeLow;
3092
3093 /* Convert timestamps to Unix format. */
3094 buf->st_mtime = convert_time (info.ftLastWriteTime);
3095 buf->st_atime = convert_time (info.ftLastAccessTime);
3096 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
3097 buf->st_ctime = convert_time (info.ftCreationTime);
3098 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
3099
3100 /* determine rwx permissions */
3101 if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
3102 permission = S_IREAD;
3103 else
3104 permission = S_IREAD | S_IWRITE;
3105
3106 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
3107 permission |= S_IEXEC;
3108 else
3109 {
3110 #if 0 /* no way of knowing the filename */
3111 char * p = strrchr (name, '.');
3112 if (p != NULL &&
3113 (xstrcasecmp (p, ".exe") == 0 ||
3114 xstrcasecmp (p, ".com") == 0 ||
3115 xstrcasecmp (p, ".bat") == 0 ||
3116 xstrcasecmp (p, ".cmd") == 0))
3117 permission |= S_IEXEC;
3118 #endif
3119 }
3120
3121 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
3122
3123 return 0;
3124 }
3125
3126 int
3127 utime (const char *name, struct utimbuf *times)
3128 {
3129 struct utimbuf deftime;
3130 HANDLE fh;
3131 FILETIME mtime;
3132 FILETIME atime;
3133
3134 if (times == NULL)
3135 {
3136 deftime.modtime = deftime.actime = time (NULL);
3137 times = &deftime;
3138 }
3139
3140 /* Need write access to set times. */
3141 fh = CreateFile (name, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
3142 0, OPEN_EXISTING, 0, NULL);
3143 if (fh)
3144 {
3145 convert_from_time_t (times->actime, &atime);
3146 convert_from_time_t (times->modtime, &mtime);
3147 if (!SetFileTime (fh, NULL, &atime, &mtime))
3148 {
3149 CloseHandle (fh);
3150 errno = EACCES;
3151 return -1;
3152 }
3153 CloseHandle (fh);
3154 }
3155 else
3156 {
3157 errno = EINVAL;
3158 return -1;
3159 }
3160 return 0;
3161 }
3162
3163 #ifdef HAVE_SOCKETS
3164
3165 /* Wrappers for winsock functions to map between our file descriptors
3166 and winsock's handles; also set h_errno for convenience.
3167
3168 To allow Emacs to run on systems which don't have winsock support
3169 installed, we dynamically link to winsock on startup if present, and
3170 otherwise provide the minimum necessary functionality
3171 (eg. gethostname). */
3172
3173 /* function pointers for relevant socket functions */
3174 int (PASCAL *pfn_WSAStartup) (WORD wVersionRequired, LPWSADATA lpWSAData);
3175 void (PASCAL *pfn_WSASetLastError) (int iError);
3176 int (PASCAL *pfn_WSAGetLastError) (void);
3177 int (PASCAL *pfn_WSAEventSelect) (SOCKET s, HANDLE hEventObject, long lNetworkEvents);
3178 HANDLE (PASCAL *pfn_WSACreateEvent) (void);
3179 int (PASCAL *pfn_WSACloseEvent) (HANDLE hEvent);
3180 int (PASCAL *pfn_socket) (int af, int type, int protocol);
3181 int (PASCAL *pfn_bind) (SOCKET s, const struct sockaddr *addr, int namelen);
3182 int (PASCAL *pfn_connect) (SOCKET s, const struct sockaddr *addr, int namelen);
3183 int (PASCAL *pfn_ioctlsocket) (SOCKET s, long cmd, u_long *argp);
3184 int (PASCAL *pfn_recv) (SOCKET s, char * buf, int len, int flags);
3185 int (PASCAL *pfn_send) (SOCKET s, const char * buf, int len, int flags);
3186 int (PASCAL *pfn_closesocket) (SOCKET s);
3187 int (PASCAL *pfn_shutdown) (SOCKET s, int how);
3188 int (PASCAL *pfn_WSACleanup) (void);
3189
3190 u_short (PASCAL *pfn_htons) (u_short hostshort);
3191 u_short (PASCAL *pfn_ntohs) (u_short netshort);
3192 unsigned long (PASCAL *pfn_inet_addr) (const char * cp);
3193 int (PASCAL *pfn_gethostname) (char * name, int namelen);
3194 struct hostent * (PASCAL *pfn_gethostbyname) (const char * name);
3195 struct servent * (PASCAL *pfn_getservbyname) (const char * name, const char * proto);
3196 int (PASCAL *pfn_getpeername) (SOCKET s, struct sockaddr *addr, int * namelen);
3197 int (PASCAL *pfn_setsockopt) (SOCKET s, int level, int optname,
3198 const char * optval, int optlen);
3199 int (PASCAL *pfn_listen) (SOCKET s, int backlog);
3200 int (PASCAL *pfn_getsockname) (SOCKET s, struct sockaddr * name,
3201 int * namelen);
3202 SOCKET (PASCAL *pfn_accept) (SOCKET s, struct sockaddr * addr, int * addrlen);
3203 int (PASCAL *pfn_recvfrom) (SOCKET s, char * buf, int len, int flags,
3204 struct sockaddr * from, int * fromlen);
3205 int (PASCAL *pfn_sendto) (SOCKET s, const char * buf, int len, int flags,
3206 const struct sockaddr * to, int tolen);
3207
3208 /* SetHandleInformation is only needed to make sockets non-inheritable. */
3209 BOOL (WINAPI *pfn_SetHandleInformation) (HANDLE object, DWORD mask, DWORD flags);
3210 #ifndef HANDLE_FLAG_INHERIT
3211 #define HANDLE_FLAG_INHERIT 1
3212 #endif
3213
3214 HANDLE winsock_lib;
3215 static int winsock_inuse;
3216
3217 BOOL
3218 term_winsock (void)
3219 {
3220 if (winsock_lib != NULL && winsock_inuse == 0)
3221 {
3222 /* Not sure what would cause WSAENETDOWN, or even if it can happen
3223 after WSAStartup returns successfully, but it seems reasonable
3224 to allow unloading winsock anyway in that case. */
3225 if (pfn_WSACleanup () == 0 ||
3226 pfn_WSAGetLastError () == WSAENETDOWN)
3227 {
3228 if (FreeLibrary (winsock_lib))
3229 winsock_lib = NULL;
3230 return TRUE;
3231 }
3232 }
3233 return FALSE;
3234 }
3235
3236 BOOL
3237 init_winsock (int load_now)
3238 {
3239 WSADATA winsockData;
3240
3241 if (winsock_lib != NULL)
3242 return TRUE;
3243
3244 pfn_SetHandleInformation = NULL;
3245 pfn_SetHandleInformation
3246 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
3247 "SetHandleInformation");
3248
3249 winsock_lib = LoadLibrary ("Ws2_32.dll");
3250
3251 if (winsock_lib != NULL)
3252 {
3253 /* dynamically link to socket functions */
3254
3255 #define LOAD_PROC(fn) \
3256 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
3257 goto fail;
3258
3259 LOAD_PROC( WSAStartup );
3260 LOAD_PROC( WSASetLastError );
3261 LOAD_PROC( WSAGetLastError );
3262 LOAD_PROC( WSAEventSelect );
3263 LOAD_PROC( WSACreateEvent );
3264 LOAD_PROC( WSACloseEvent );
3265 LOAD_PROC( socket );
3266 LOAD_PROC( bind );
3267 LOAD_PROC( connect );
3268 LOAD_PROC( ioctlsocket );
3269 LOAD_PROC( recv );
3270 LOAD_PROC( send );
3271 LOAD_PROC( closesocket );
3272 LOAD_PROC( shutdown );
3273 LOAD_PROC( htons );
3274 LOAD_PROC( ntohs );
3275 LOAD_PROC( inet_addr );
3276 LOAD_PROC( gethostname );
3277 LOAD_PROC( gethostbyname );
3278 LOAD_PROC( getservbyname );
3279 LOAD_PROC( getpeername );
3280 LOAD_PROC( WSACleanup );
3281 LOAD_PROC( setsockopt );
3282 LOAD_PROC( listen );
3283 LOAD_PROC( getsockname );
3284 LOAD_PROC( accept );
3285 LOAD_PROC( recvfrom );
3286 LOAD_PROC( sendto );
3287 #undef LOAD_PROC
3288
3289 /* specify version 1.1 of winsock */
3290 if (pfn_WSAStartup (0x101, &winsockData) == 0)
3291 {
3292 if (winsockData.wVersion != 0x101)
3293 goto fail;
3294
3295 if (!load_now)
3296 {
3297 /* Report that winsock exists and is usable, but leave
3298 socket functions disabled. I am assuming that calling
3299 WSAStartup does not require any network interaction,
3300 and in particular does not cause or require a dial-up
3301 connection to be established. */
3302
3303 pfn_WSACleanup ();
3304 FreeLibrary (winsock_lib);
3305 winsock_lib = NULL;
3306 }
3307 winsock_inuse = 0;
3308 return TRUE;
3309 }
3310
3311 fail:
3312 FreeLibrary (winsock_lib);
3313 winsock_lib = NULL;
3314 }
3315
3316 return FALSE;
3317 }
3318
3319
3320 int h_errno = 0;
3321
3322 /* function to set h_errno for compatability; map winsock error codes to
3323 normal system codes where they overlap (non-overlapping definitions
3324 are already in <sys/socket.h> */
3325 static void
3326 set_errno ()
3327 {
3328 if (winsock_lib == NULL)
3329 h_errno = EINVAL;
3330 else
3331 h_errno = pfn_WSAGetLastError ();
3332
3333 switch (h_errno)
3334 {
3335 case WSAEACCES: h_errno = EACCES; break;
3336 case WSAEBADF: h_errno = EBADF; break;
3337 case WSAEFAULT: h_errno = EFAULT; break;
3338 case WSAEINTR: h_errno = EINTR; break;
3339 case WSAEINVAL: h_errno = EINVAL; break;
3340 case WSAEMFILE: h_errno = EMFILE; break;
3341 case WSAENAMETOOLONG: h_errno = ENAMETOOLONG; break;
3342 case WSAENOTEMPTY: h_errno = ENOTEMPTY; break;
3343 }
3344 errno = h_errno;
3345 }
3346
3347 static void
3348 check_errno ()
3349 {
3350 if (h_errno == 0 && winsock_lib != NULL)
3351 pfn_WSASetLastError (0);
3352 }
3353
3354 /* Extend strerror to handle the winsock-specific error codes. */
3355 struct {
3356 int errnum;
3357 char * msg;
3358 } _wsa_errlist[] = {
3359 WSAEINTR , "Interrupted function call",
3360 WSAEBADF , "Bad file descriptor",
3361 WSAEACCES , "Permission denied",
3362 WSAEFAULT , "Bad address",
3363 WSAEINVAL , "Invalid argument",
3364 WSAEMFILE , "Too many open files",
3365
3366 WSAEWOULDBLOCK , "Resource temporarily unavailable",
3367 WSAEINPROGRESS , "Operation now in progress",
3368 WSAEALREADY , "Operation already in progress",
3369 WSAENOTSOCK , "Socket operation on non-socket",
3370 WSAEDESTADDRREQ , "Destination address required",
3371 WSAEMSGSIZE , "Message too long",
3372 WSAEPROTOTYPE , "Protocol wrong type for socket",
3373 WSAENOPROTOOPT , "Bad protocol option",
3374 WSAEPROTONOSUPPORT , "Protocol not supported",
3375 WSAESOCKTNOSUPPORT , "Socket type not supported",
3376 WSAEOPNOTSUPP , "Operation not supported",
3377 WSAEPFNOSUPPORT , "Protocol family not supported",
3378 WSAEAFNOSUPPORT , "Address family not supported by protocol family",
3379 WSAEADDRINUSE , "Address already in use",
3380 WSAEADDRNOTAVAIL , "Cannot assign requested address",
3381 WSAENETDOWN , "Network is down",
3382 WSAENETUNREACH , "Network is unreachable",
3383 WSAENETRESET , "Network dropped connection on reset",
3384 WSAECONNABORTED , "Software caused connection abort",
3385 WSAECONNRESET , "Connection reset by peer",
3386 WSAENOBUFS , "No buffer space available",
3387 WSAEISCONN , "Socket is already connected",
3388 WSAENOTCONN , "Socket is not connected",
3389 WSAESHUTDOWN , "Cannot send after socket shutdown",
3390 WSAETOOMANYREFS , "Too many references", /* not sure */
3391 WSAETIMEDOUT , "Connection timed out",
3392 WSAECONNREFUSED , "Connection refused",
3393 WSAELOOP , "Network loop", /* not sure */
3394 WSAENAMETOOLONG , "Name is too long",
3395 WSAEHOSTDOWN , "Host is down",
3396 WSAEHOSTUNREACH , "No route to host",
3397 WSAENOTEMPTY , "Buffer not empty", /* not sure */
3398 WSAEPROCLIM , "Too many processes",
3399 WSAEUSERS , "Too many users", /* not sure */
3400 WSAEDQUOT , "Double quote in host name", /* really not sure */
3401 WSAESTALE , "Data is stale", /* not sure */
3402 WSAEREMOTE , "Remote error", /* not sure */
3403
3404 WSASYSNOTREADY , "Network subsystem is unavailable",
3405 WSAVERNOTSUPPORTED , "WINSOCK.DLL version out of range",
3406 WSANOTINITIALISED , "Winsock not initialized successfully",
3407 WSAEDISCON , "Graceful shutdown in progress",
3408 #ifdef WSAENOMORE
3409 WSAENOMORE , "No more operations allowed", /* not sure */
3410 WSAECANCELLED , "Operation cancelled", /* not sure */
3411 WSAEINVALIDPROCTABLE , "Invalid procedure table from service provider",
3412 WSAEINVALIDPROVIDER , "Invalid service provider version number",
3413 WSAEPROVIDERFAILEDINIT , "Unable to initialize a service provider",
3414 WSASYSCALLFAILURE , "System call failure",
3415 WSASERVICE_NOT_FOUND , "Service not found", /* not sure */
3416 WSATYPE_NOT_FOUND , "Class type not found",
3417 WSA_E_NO_MORE , "No more resources available", /* really not sure */
3418 WSA_E_CANCELLED , "Operation already cancelled", /* really not sure */
3419 WSAEREFUSED , "Operation refused", /* not sure */
3420 #endif
3421
3422 WSAHOST_NOT_FOUND , "Host not found",
3423 WSATRY_AGAIN , "Authoritative host not found during name lookup",
3424 WSANO_RECOVERY , "Non-recoverable error during name lookup",
3425 WSANO_DATA , "Valid name, no data record of requested type",
3426
3427 -1, NULL
3428 };
3429
3430 char *
3431 sys_strerror(int error_no)
3432 {
3433 int i;
3434 static char unknown_msg[40];
3435
3436 if (error_no >= 0 && error_no < sys_nerr)
3437 return sys_errlist[error_no];
3438
3439 for (i = 0; _wsa_errlist[i].errnum >= 0; i++)
3440 if (_wsa_errlist[i].errnum == error_no)
3441 return _wsa_errlist[i].msg;
3442
3443 sprintf(unknown_msg, "Unidentified error: %d", error_no);
3444 return unknown_msg;
3445 }
3446
3447 /* [andrewi 3-May-96] I've had conflicting results using both methods,
3448 but I believe the method of keeping the socket handle separate (and
3449 insuring it is not inheritable) is the correct one. */
3450
3451 //#define SOCK_REPLACE_HANDLE
3452
3453 #ifdef SOCK_REPLACE_HANDLE
3454 #define SOCK_HANDLE(fd) ((SOCKET) _get_osfhandle (fd))
3455 #else
3456 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
3457 #endif
3458
3459 int socket_to_fd (SOCKET s);
3460
3461 int
3462 sys_socket(int af, int type, int protocol)
3463 {
3464 SOCKET s;
3465
3466 if (winsock_lib == NULL)
3467 {
3468 h_errno = ENETDOWN;
3469 return INVALID_SOCKET;
3470 }
3471
3472 check_errno ();
3473
3474 /* call the real socket function */
3475 s = pfn_socket (af, type, protocol);
3476
3477 if (s != INVALID_SOCKET)
3478 return socket_to_fd (s);
3479
3480 set_errno ();
3481 return -1;
3482 }
3483
3484 /* Convert a SOCKET to a file descriptor. */
3485 int
3486 socket_to_fd (SOCKET s)
3487 {
3488 int fd;
3489 child_process * cp;
3490
3491 /* Although under NT 3.5 _open_osfhandle will accept a socket
3492 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
3493 that does not work under NT 3.1. However, we can get the same
3494 effect by using a backdoor function to replace an existing
3495 descriptor handle with the one we want. */
3496
3497 /* allocate a file descriptor (with appropriate flags) */
3498 fd = _open ("NUL:", _O_RDWR);
3499 if (fd >= 0)
3500 {
3501 #ifdef SOCK_REPLACE_HANDLE
3502 /* now replace handle to NUL with our socket handle */
3503 CloseHandle ((HANDLE) _get_osfhandle (fd));
3504 _free_osfhnd (fd);
3505 _set_osfhnd (fd, s);
3506 /* setmode (fd, _O_BINARY); */
3507 #else
3508 /* Make a non-inheritable copy of the socket handle. Note
3509 that it is possible that sockets aren't actually kernel
3510 handles, which appears to be the case on Windows 9x when
3511 the MS Proxy winsock client is installed. */
3512 {
3513 /* Apparently there is a bug in NT 3.51 with some service
3514 packs, which prevents using DuplicateHandle to make a
3515 socket handle non-inheritable (causes WSACleanup to
3516 hang). The work-around is to use SetHandleInformation
3517 instead if it is available and implemented. */
3518 if (pfn_SetHandleInformation)
3519 {
3520 pfn_SetHandleInformation ((HANDLE) s, HANDLE_FLAG_INHERIT, 0);
3521 }
3522 else
3523 {
3524 HANDLE parent = GetCurrentProcess ();
3525 HANDLE new_s = INVALID_HANDLE_VALUE;
3526
3527 if (DuplicateHandle (parent,
3528 (HANDLE) s,
3529 parent,
3530 &new_s,
3531 0,
3532 FALSE,
3533 DUPLICATE_SAME_ACCESS))
3534 {
3535 /* It is possible that DuplicateHandle succeeds even
3536 though the socket wasn't really a kernel handle,
3537 because a real handle has the same value. So
3538 test whether the new handle really is a socket. */
3539 long nonblocking = 0;
3540 if (pfn_ioctlsocket ((SOCKET) new_s, FIONBIO, &nonblocking) == 0)
3541 {
3542 pfn_closesocket (s);
3543 s = (SOCKET) new_s;
3544 }
3545 else
3546 {
3547 CloseHandle (new_s);
3548 }
3549 }
3550 }
3551 }
3552 fd_info[fd].hnd = (HANDLE) s;
3553 #endif
3554
3555 /* set our own internal flags */
3556 fd_info[fd].flags = FILE_SOCKET | FILE_BINARY | FILE_READ | FILE_WRITE;
3557
3558 cp = new_child ();
3559 if (cp)
3560 {
3561 cp->fd = fd;
3562 cp->status = STATUS_READ_ACKNOWLEDGED;
3563
3564 /* attach child_process to fd_info */
3565 if (fd_info[ fd ].cp != NULL)
3566 {
3567 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd));
3568 abort ();
3569 }
3570
3571 fd_info[ fd ].cp = cp;
3572
3573 /* success! */
3574 winsock_inuse++; /* count open sockets */
3575 return fd;
3576 }
3577
3578 /* clean up */
3579 _close (fd);
3580 }
3581 pfn_closesocket (s);
3582 h_errno = EMFILE;
3583 return -1;
3584 }
3585
3586
3587 int
3588 sys_bind (int s, const struct sockaddr * addr, int namelen)
3589 {
3590 if (winsock_lib == NULL)
3591 {
3592 h_errno = ENOTSOCK;
3593 return SOCKET_ERROR;
3594 }
3595
3596 check_errno ();
3597 if (fd_info[s].flags & FILE_SOCKET)
3598 {
3599 int rc = pfn_bind (SOCK_HANDLE (s), addr, namelen);
3600 if (rc == SOCKET_ERROR)
3601 set_errno ();
3602 return rc;
3603 }
3604 h_errno = ENOTSOCK;
3605 return SOCKET_ERROR;
3606 }
3607
3608
3609 int
3610 sys_connect (int s, const struct sockaddr * name, int namelen)
3611 {
3612 if (winsock_lib == NULL)
3613 {
3614 h_errno = ENOTSOCK;
3615 return SOCKET_ERROR;
3616 }
3617
3618 check_errno ();
3619 if (fd_info[s].flags & FILE_SOCKET)
3620 {
3621 int rc = pfn_connect (SOCK_HANDLE (s), name, namelen);
3622 if (rc == SOCKET_ERROR)
3623 set_errno ();
3624 return rc;
3625 }
3626 h_errno = ENOTSOCK;
3627 return SOCKET_ERROR;
3628 }
3629
3630 u_short
3631 sys_htons (u_short hostshort)
3632 {
3633 return (winsock_lib != NULL) ?
3634 pfn_htons (hostshort) : hostshort;
3635 }
3636
3637 u_short
3638 sys_ntohs (u_short netshort)
3639 {
3640 return (winsock_lib != NULL) ?
3641 pfn_ntohs (netshort) : netshort;
3642 }
3643
3644 unsigned long
3645 sys_inet_addr (const char * cp)
3646 {
3647 return (winsock_lib != NULL) ?
3648 pfn_inet_addr (cp) : INADDR_NONE;
3649 }
3650
3651 int
3652 sys_gethostname (char * name, int namelen)
3653 {
3654 if (winsock_lib != NULL)
3655 return pfn_gethostname (name, namelen);
3656
3657 if (namelen > MAX_COMPUTERNAME_LENGTH)
3658 return !GetComputerName (name, (DWORD *)&namelen);
3659
3660 h_errno = EFAULT;
3661 return SOCKET_ERROR;
3662 }
3663
3664 struct hostent *
3665 sys_gethostbyname(const char * name)
3666 {
3667 struct hostent * host;
3668
3669 if (winsock_lib == NULL)
3670 {
3671 h_errno = ENETDOWN;
3672 return NULL;
3673 }
3674
3675 check_errno ();
3676 host = pfn_gethostbyname (name);
3677 if (!host)
3678 set_errno ();
3679 return host;
3680 }
3681
3682 struct servent *
3683 sys_getservbyname(const char * name, const char * proto)
3684 {
3685 struct servent * serv;
3686
3687 if (winsock_lib == NULL)
3688 {
3689 h_errno = ENETDOWN;
3690 return NULL;
3691 }
3692
3693 check_errno ();
3694 serv = pfn_getservbyname (name, proto);
3695 if (!serv)
3696 set_errno ();
3697 return serv;
3698 }
3699
3700 int
3701 sys_getpeername (int s, struct sockaddr *addr, int * namelen)
3702 {
3703 if (winsock_lib == NULL)
3704 {
3705 h_errno = ENETDOWN;
3706 return SOCKET_ERROR;
3707 }
3708
3709 check_errno ();
3710 if (fd_info[s].flags & FILE_SOCKET)
3711 {
3712 int rc = pfn_getpeername (SOCK_HANDLE (s), addr, namelen);
3713 if (rc == SOCKET_ERROR)
3714 set_errno ();
3715 return rc;
3716 }
3717 h_errno = ENOTSOCK;
3718 return SOCKET_ERROR;
3719 }
3720
3721
3722 int
3723 sys_shutdown (int s, int how)
3724 {
3725 if (winsock_lib == NULL)
3726 {
3727 h_errno = ENETDOWN;
3728 return SOCKET_ERROR;
3729 }
3730
3731 check_errno ();
3732 if (fd_info[s].flags & FILE_SOCKET)
3733 {
3734 int rc = pfn_shutdown (SOCK_HANDLE (s), how);
3735 if (rc == SOCKET_ERROR)
3736 set_errno ();
3737 return rc;
3738 }
3739 h_errno = ENOTSOCK;
3740 return SOCKET_ERROR;
3741 }
3742
3743 int
3744 sys_setsockopt (int s, int level, int optname, const void * optval, int optlen)
3745 {
3746 if (winsock_lib == NULL)
3747 {
3748 h_errno = ENETDOWN;
3749 return SOCKET_ERROR;
3750 }
3751
3752 check_errno ();
3753 if (fd_info[s].flags & FILE_SOCKET)
3754 {
3755 int rc = pfn_setsockopt (SOCK_HANDLE (s), level, optname,
3756 (const char *)optval, optlen);
3757 if (rc == SOCKET_ERROR)
3758 set_errno ();
3759 return rc;
3760 }
3761 h_errno = ENOTSOCK;
3762 return SOCKET_ERROR;
3763 }
3764
3765 int
3766 sys_listen (int s, int backlog)
3767 {
3768 if (winsock_lib == NULL)
3769 {
3770 h_errno = ENETDOWN;
3771 return SOCKET_ERROR;
3772 }
3773
3774 check_errno ();
3775 if (fd_info[s].flags & FILE_SOCKET)
3776 {
3777 int rc = pfn_listen (SOCK_HANDLE (s), backlog);
3778 if (rc == SOCKET_ERROR)
3779 set_errno ();
3780 else
3781 fd_info[s].flags |= FILE_LISTEN;
3782 return rc;
3783 }
3784 h_errno = ENOTSOCK;
3785 return SOCKET_ERROR;
3786 }
3787
3788 int
3789 sys_getsockname (int s, struct sockaddr * name, int * namelen)
3790 {
3791 if (winsock_lib == NULL)
3792 {
3793 h_errno = ENETDOWN;
3794 return SOCKET_ERROR;
3795 }
3796
3797 check_errno ();
3798 if (fd_info[s].flags & FILE_SOCKET)
3799 {
3800 int rc = pfn_getsockname (SOCK_HANDLE (s), name, namelen);
3801 if (rc == SOCKET_ERROR)
3802 set_errno ();
3803 return rc;
3804 }
3805 h_errno = ENOTSOCK;
3806 return SOCKET_ERROR;
3807 }
3808
3809 int
3810 sys_accept (int s, struct sockaddr * addr, int * addrlen)
3811 {
3812 if (winsock_lib == NULL)
3813 {
3814 h_errno = ENETDOWN;
3815 return -1;
3816 }
3817
3818 check_errno ();
3819 if (fd_info[s].flags & FILE_LISTEN)
3820 {
3821 SOCKET t = pfn_accept (SOCK_HANDLE (s), addr, addrlen);
3822 int fd = -1;
3823 if (t == INVALID_SOCKET)
3824 set_errno ();
3825 else
3826 fd = socket_to_fd (t);
3827
3828 fd_info[s].cp->status = STATUS_READ_ACKNOWLEDGED;
3829 ResetEvent (fd_info[s].cp->char_avail);
3830 return fd;
3831 }
3832 h_errno = ENOTSOCK;
3833 return -1;
3834 }
3835
3836 int
3837 sys_recvfrom (int s, char * buf, int len, int flags,
3838 struct sockaddr * from, int * fromlen)
3839 {
3840 if (winsock_lib == NULL)
3841 {
3842 h_errno = ENETDOWN;
3843 return SOCKET_ERROR;
3844 }
3845
3846 check_errno ();
3847 if (fd_info[s].flags & FILE_SOCKET)
3848 {
3849 int rc = pfn_recvfrom (SOCK_HANDLE (s), buf, len, flags, from, fromlen);
3850 if (rc == SOCKET_ERROR)
3851 set_errno ();
3852 return rc;
3853 }
3854 h_errno = ENOTSOCK;
3855 return SOCKET_ERROR;
3856 }
3857
3858 int
3859 sys_sendto (int s, const char * buf, int len, int flags,
3860 const struct sockaddr * to, int tolen)
3861 {
3862 if (winsock_lib == NULL)
3863 {
3864 h_errno = ENETDOWN;
3865 return SOCKET_ERROR;
3866 }
3867
3868 check_errno ();
3869 if (fd_info[s].flags & FILE_SOCKET)
3870 {
3871 int rc = pfn_sendto (SOCK_HANDLE (s), buf, len, flags, to, tolen);
3872 if (rc == SOCKET_ERROR)
3873 set_errno ();
3874 return rc;
3875 }
3876 h_errno = ENOTSOCK;
3877 return SOCKET_ERROR;
3878 }
3879
3880 /* Windows does not have an fcntl function. Provide an implementation
3881 solely for making sockets non-blocking. */
3882 int
3883 fcntl (int s, int cmd, int options)
3884 {
3885 if (winsock_lib == NULL)
3886 {
3887 h_errno = ENETDOWN;
3888 return -1;
3889 }
3890
3891 check_errno ();
3892 if (fd_info[s].flags & FILE_SOCKET)
3893 {
3894 if (cmd == F_SETFL && options == O_NDELAY)
3895 {
3896 unsigned long nblock = 1;
3897 int rc = pfn_ioctlsocket (SOCK_HANDLE (s), FIONBIO, &nblock);
3898 if (rc == SOCKET_ERROR)
3899 set_errno();
3900 /* Keep track of the fact that we set this to non-blocking. */
3901 fd_info[s].flags |= FILE_NDELAY;
3902 return rc;
3903 }
3904 else
3905 {
3906 h_errno = EINVAL;
3907 return SOCKET_ERROR;
3908 }
3909 }
3910 h_errno = ENOTSOCK;
3911 return SOCKET_ERROR;
3912 }
3913
3914 #endif /* HAVE_SOCKETS */
3915
3916
3917 /* Shadow main io functions: we need to handle pipes and sockets more
3918 intelligently, and implement non-blocking mode as well. */
3919
3920 int
3921 sys_close (int fd)
3922 {
3923 int rc;
3924
3925 if (fd < 0)
3926 {
3927 errno = EBADF;
3928 return -1;
3929 }
3930
3931 if (fd < MAXDESC && fd_info[fd].cp)
3932 {
3933 child_process * cp = fd_info[fd].cp;
3934
3935 fd_info[fd].cp = NULL;
3936
3937 if (CHILD_ACTIVE (cp))
3938 {
3939 /* if last descriptor to active child_process then cleanup */
3940 int i;
3941 for (i = 0; i < MAXDESC; i++)
3942 {
3943 if (i == fd)
3944 continue;
3945 if (fd_info[i].cp == cp)
3946 break;
3947 }
3948 if (i == MAXDESC)
3949 {
3950 #ifdef HAVE_SOCKETS
3951 if (fd_info[fd].flags & FILE_SOCKET)
3952 {
3953 #ifndef SOCK_REPLACE_HANDLE
3954 if (winsock_lib == NULL) abort ();
3955
3956 pfn_shutdown (SOCK_HANDLE (fd), 2);
3957 rc = pfn_closesocket (SOCK_HANDLE (fd));
3958 #endif
3959 winsock_inuse--; /* count open sockets */
3960 }
3961 #endif
3962 delete_child (cp);
3963 }
3964 }
3965 }
3966
3967 /* Note that sockets do not need special treatment here (at least on
3968 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
3969 closesocket is equivalent to CloseHandle, which is to be expected
3970 because socket handles are fully fledged kernel handles. */
3971 rc = _close (fd);
3972
3973 if (rc == 0 && fd < MAXDESC)
3974 fd_info[fd].flags = 0;
3975
3976 return rc;
3977 }
3978
3979 int
3980 sys_dup (int fd)
3981 {
3982 int new_fd;
3983
3984 new_fd = _dup (fd);
3985 if (new_fd >= 0 && new_fd < MAXDESC)
3986 {
3987 /* duplicate our internal info as well */
3988 fd_info[new_fd] = fd_info[fd];
3989 }
3990 return new_fd;
3991 }
3992
3993
3994 int
3995 sys_dup2 (int src, int dst)
3996 {
3997 int rc;
3998
3999 if (dst < 0 || dst >= MAXDESC)
4000 {
4001 errno = EBADF;
4002 return -1;
4003 }
4004
4005 /* make sure we close the destination first if it's a pipe or socket */
4006 if (src != dst && fd_info[dst].flags != 0)
4007 sys_close (dst);
4008
4009 rc = _dup2 (src, dst);
4010 if (rc == 0)
4011 {
4012 /* duplicate our internal info as well */
4013 fd_info[dst] = fd_info[src];
4014 }
4015 return rc;
4016 }
4017
4018 /* Unix pipe() has only one arg */
4019 int
4020 sys_pipe (int * phandles)
4021 {
4022 int rc;
4023 unsigned flags;
4024
4025 /* make pipe handles non-inheritable; when we spawn a child, we
4026 replace the relevant handle with an inheritable one. Also put
4027 pipes into binary mode; we will do text mode translation ourselves
4028 if required. */
4029 rc = _pipe (phandles, 0, _O_NOINHERIT | _O_BINARY);
4030
4031 if (rc == 0)
4032 {
4033 /* Protect against overflow, since Windows can open more handles than
4034 our fd_info array has room for. */
4035 if (phandles[0] >= MAXDESC || phandles[1] >= MAXDESC)
4036 {
4037 _close (phandles[0]);
4038 _close (phandles[1]);
4039 rc = -1;
4040 }
4041 else
4042 {
4043 flags = FILE_PIPE | FILE_READ | FILE_BINARY;
4044 fd_info[phandles[0]].flags = flags;
4045
4046 flags = FILE_PIPE | FILE_WRITE | FILE_BINARY;
4047 fd_info[phandles[1]].flags = flags;
4048 }
4049 }
4050
4051 return rc;
4052 }
4053
4054 /* From ntproc.c */
4055 extern int w32_pipe_read_delay;
4056
4057 /* Function to do blocking read of one byte, needed to implement
4058 select. It is only allowed on sockets and pipes. */
4059 int
4060 _sys_read_ahead (int fd)
4061 {
4062 child_process * cp;
4063 int rc;
4064
4065 if (fd < 0 || fd >= MAXDESC)
4066 return STATUS_READ_ERROR;
4067
4068 cp = fd_info[fd].cp;
4069
4070 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
4071 return STATUS_READ_ERROR;
4072
4073 if ((fd_info[fd].flags & (FILE_PIPE | FILE_SERIAL | FILE_SOCKET)) == 0
4074 || (fd_info[fd].flags & FILE_READ) == 0)
4075 {
4076 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd));
4077 abort ();
4078 }
4079
4080 cp->status = STATUS_READ_IN_PROGRESS;
4081
4082 if (fd_info[fd].flags & FILE_PIPE)
4083 {
4084 rc = _read (fd, &cp->chr, sizeof (char));
4085
4086 /* Give subprocess time to buffer some more output for us before
4087 reporting that input is available; we need this because Windows 95
4088 connects DOS programs to pipes by making the pipe appear to be
4089 the normal console stdout - as a result most DOS programs will
4090 write to stdout without buffering, ie. one character at a
4091 time. Even some W32 programs do this - "dir" in a command
4092 shell on NT is very slow if we don't do this. */
4093 if (rc > 0)
4094 {
4095 int wait = w32_pipe_read_delay;
4096
4097 if (wait > 0)
4098 Sleep (wait);
4099 else if (wait < 0)
4100 while (++wait <= 0)
4101 /* Yield remainder of our time slice, effectively giving a
4102 temporary priority boost to the child process. */
4103 Sleep (0);
4104 }
4105 }
4106 else if (fd_info[fd].flags & FILE_SERIAL)
4107 {
4108 HANDLE hnd = fd_info[fd].hnd;
4109 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
4110 COMMTIMEOUTS ct;
4111
4112 /* Configure timeouts for blocking read. */
4113 if (!GetCommTimeouts (hnd, &ct))
4114 return STATUS_READ_ERROR;
4115 ct.ReadIntervalTimeout = 0;
4116 ct.ReadTotalTimeoutMultiplier = 0;
4117 ct.ReadTotalTimeoutConstant = 0;
4118 if (!SetCommTimeouts (hnd, &ct))
4119 return STATUS_READ_ERROR;
4120
4121 if (!ReadFile (hnd, &cp->chr, sizeof (char), (DWORD*) &rc, ovl))
4122 {
4123 if (GetLastError () != ERROR_IO_PENDING)
4124 return STATUS_READ_ERROR;
4125 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
4126 return STATUS_READ_ERROR;
4127 }
4128 }
4129 #ifdef HAVE_SOCKETS
4130 else if (fd_info[fd].flags & FILE_SOCKET)
4131 {
4132 unsigned long nblock = 0;
4133 /* We always want this to block, so temporarily disable NDELAY. */
4134 if (fd_info[fd].flags & FILE_NDELAY)
4135 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
4136
4137 rc = pfn_recv (SOCK_HANDLE (fd), &cp->chr, sizeof (char), 0);
4138
4139 if (fd_info[fd].flags & FILE_NDELAY)
4140 {
4141 nblock = 1;
4142 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
4143 }
4144 }
4145 #endif
4146
4147 if (rc == sizeof (char))
4148 cp->status = STATUS_READ_SUCCEEDED;
4149 else
4150 cp->status = STATUS_READ_FAILED;
4151
4152 return cp->status;
4153 }
4154
4155 int
4156 _sys_wait_accept (int fd)
4157 {
4158 HANDLE hEv;
4159 child_process * cp;
4160 int rc;
4161
4162 if (fd < 0 || fd >= MAXDESC)
4163 return STATUS_READ_ERROR;
4164
4165 cp = fd_info[fd].cp;
4166
4167 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
4168 return STATUS_READ_ERROR;
4169
4170 cp->status = STATUS_READ_FAILED;
4171
4172 hEv = pfn_WSACreateEvent ();
4173 rc = pfn_WSAEventSelect (SOCK_HANDLE (fd), hEv, FD_ACCEPT);
4174 if (rc != SOCKET_ERROR)
4175 {
4176 rc = WaitForSingleObject (hEv, INFINITE);
4177 pfn_WSAEventSelect (SOCK_HANDLE (fd), NULL, 0);
4178 if (rc == WAIT_OBJECT_0)
4179 cp->status = STATUS_READ_SUCCEEDED;
4180 }
4181 pfn_WSACloseEvent (hEv);
4182
4183 return cp->status;
4184 }
4185
4186 int
4187 sys_read (int fd, char * buffer, unsigned int count)
4188 {
4189 int nchars;
4190 int to_read;
4191 DWORD waiting;
4192 char * orig_buffer = buffer;
4193
4194 if (fd < 0)
4195 {
4196 errno = EBADF;
4197 return -1;
4198 }
4199
4200 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
4201 {
4202 child_process *cp = fd_info[fd].cp;
4203
4204 if ((fd_info[fd].flags & FILE_READ) == 0)
4205 {
4206 errno = EBADF;
4207 return -1;
4208 }
4209
4210 nchars = 0;
4211
4212 /* re-read CR carried over from last read */
4213 if (fd_info[fd].flags & FILE_LAST_CR)
4214 {
4215 if (fd_info[fd].flags & FILE_BINARY) abort ();
4216 *buffer++ = 0x0d;
4217 count--;
4218 nchars++;
4219 fd_info[fd].flags &= ~FILE_LAST_CR;
4220 }
4221
4222 /* presence of a child_process structure means we are operating in
4223 non-blocking mode - otherwise we just call _read directly.
4224 Note that the child_process structure might be missing because
4225 reap_subprocess has been called; in this case the pipe is
4226 already broken, so calling _read on it is okay. */
4227 if (cp)
4228 {
4229 int current_status = cp->status;
4230
4231 switch (current_status)
4232 {
4233 case STATUS_READ_FAILED:
4234 case STATUS_READ_ERROR:
4235 /* report normal EOF if nothing in buffer */
4236 if (nchars <= 0)
4237 fd_info[fd].flags |= FILE_AT_EOF;
4238 return nchars;
4239
4240 case STATUS_READ_READY:
4241 case STATUS_READ_IN_PROGRESS:
4242 DebPrint (("sys_read called when read is in progress\n"));
4243 errno = EWOULDBLOCK;
4244 return -1;
4245
4246 case STATUS_READ_SUCCEEDED:
4247 /* consume read-ahead char */
4248 *buffer++ = cp->chr;
4249 count--;
4250 nchars++;
4251 cp->status = STATUS_READ_ACKNOWLEDGED;
4252 ResetEvent (cp->char_avail);
4253
4254 case STATUS_READ_ACKNOWLEDGED:
4255 break;
4256
4257 default:
4258 DebPrint (("sys_read: bad status %d\n", current_status));
4259 errno = EBADF;
4260 return -1;
4261 }
4262
4263 if (fd_info[fd].flags & FILE_PIPE)
4264 {
4265 PeekNamedPipe ((HANDLE) _get_osfhandle (fd), NULL, 0, NULL, &waiting, NULL);
4266 to_read = min (waiting, (DWORD) count);
4267
4268 if (to_read > 0)
4269 nchars += _read (fd, buffer, to_read);
4270 }
4271 else if (fd_info[fd].flags & FILE_SERIAL)
4272 {
4273 HANDLE hnd = fd_info[fd].hnd;
4274 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
4275 DWORD err = 0;
4276 int rc = 0;
4277 COMMTIMEOUTS ct;
4278
4279 if (count > 0)
4280 {
4281 /* Configure timeouts for non-blocking read. */
4282 if (!GetCommTimeouts (hnd, &ct))
4283 {
4284 errno = EIO;
4285 return -1;
4286 }
4287 ct.ReadIntervalTimeout = MAXDWORD;
4288 ct.ReadTotalTimeoutMultiplier = 0;
4289 ct.ReadTotalTimeoutConstant = 0;
4290 if (!SetCommTimeouts (hnd, &ct))
4291 {
4292 errno = EIO;
4293 return -1;
4294 }
4295
4296 if (!ResetEvent (ovl->hEvent))
4297 {
4298 errno = EIO;
4299 return -1;
4300 }
4301 if (!ReadFile (hnd, buffer, count, (DWORD*) &rc, ovl))
4302 {
4303 if (GetLastError () != ERROR_IO_PENDING)
4304 {
4305 errno = EIO;
4306 return -1;
4307 }
4308 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
4309 {
4310 errno = EIO;
4311 return -1;
4312 }
4313 }
4314 nchars += rc;
4315 }
4316 }
4317 #ifdef HAVE_SOCKETS
4318 else /* FILE_SOCKET */
4319 {
4320 if (winsock_lib == NULL) abort ();
4321
4322 /* do the equivalent of a non-blocking read */
4323 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONREAD, &waiting);
4324 if (waiting == 0 && nchars == 0)
4325 {
4326 h_errno = errno = EWOULDBLOCK;
4327 return -1;
4328 }
4329
4330 if (waiting)
4331 {
4332 /* always use binary mode for sockets */
4333 int res = pfn_recv (SOCK_HANDLE (fd), buffer, count, 0);
4334 if (res == SOCKET_ERROR)
4335 {
4336 DebPrint(("sys_read.recv failed with error %d on socket %ld\n",
4337 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
4338 set_errno ();
4339 return -1;
4340 }
4341 nchars += res;
4342 }
4343 }
4344 #endif
4345 }
4346 else
4347 {
4348 int nread = _read (fd, buffer, count);
4349 if (nread >= 0)
4350 nchars += nread;
4351 else if (nchars == 0)
4352 nchars = nread;
4353 }
4354
4355 if (nchars <= 0)
4356 fd_info[fd].flags |= FILE_AT_EOF;
4357 /* Perform text mode translation if required. */
4358 else if ((fd_info[fd].flags & FILE_BINARY) == 0)
4359 {
4360 nchars = crlf_to_lf (nchars, orig_buffer);
4361 /* If buffer contains only CR, return that. To be absolutely
4362 sure we should attempt to read the next char, but in
4363 practice a CR to be followed by LF would not appear by
4364 itself in the buffer. */
4365 if (nchars > 1 && orig_buffer[nchars - 1] == 0x0d)
4366 {
4367 fd_info[fd].flags |= FILE_LAST_CR;
4368 nchars--;
4369 }
4370 }
4371 }
4372 else
4373 nchars = _read (fd, buffer, count);
4374
4375 return nchars;
4376 }
4377
4378 /* From w32xfns.c */
4379 extern HANDLE interrupt_handle;
4380
4381 /* For now, don't bother with a non-blocking mode */
4382 int
4383 sys_write (int fd, const void * buffer, unsigned int count)
4384 {
4385 int nchars;
4386
4387 if (fd < 0)
4388 {
4389 errno = EBADF;
4390 return -1;
4391 }
4392
4393 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
4394 {
4395 if ((fd_info[fd].flags & FILE_WRITE) == 0)
4396 {
4397 errno = EBADF;
4398 return -1;
4399 }
4400
4401 /* Perform text mode translation if required. */
4402 if ((fd_info[fd].flags & FILE_BINARY) == 0)
4403 {
4404 char * tmpbuf = alloca (count * 2);
4405 unsigned char * src = (void *)buffer;
4406 unsigned char * dst = tmpbuf;
4407 int nbytes = count;
4408
4409 while (1)
4410 {
4411 unsigned char *next;
4412 /* copy next line or remaining bytes */
4413 next = _memccpy (dst, src, '\n', nbytes);
4414 if (next)
4415 {
4416 /* copied one line ending with '\n' */
4417 int copied = next - dst;
4418 nbytes -= copied;
4419 src += copied;
4420 /* insert '\r' before '\n' */
4421 next[-1] = '\r';
4422 next[0] = '\n';
4423 dst = next + 1;
4424 count++;
4425 }
4426 else
4427 /* copied remaining partial line -> now finished */
4428 break;
4429 }
4430 buffer = tmpbuf;
4431 }
4432 }
4433
4434 if (fd < MAXDESC && fd_info[fd].flags & FILE_SERIAL)
4435 {
4436 HANDLE hnd = (HANDLE) _get_osfhandle (fd);
4437 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_write;
4438 HANDLE wait_hnd[2] = { interrupt_handle, ovl->hEvent };
4439 DWORD active = 0;
4440
4441 if (!WriteFile (hnd, buffer, count, (DWORD*) &nchars, ovl))
4442 {
4443 if (GetLastError () != ERROR_IO_PENDING)
4444 {
4445 errno = EIO;
4446 return -1;
4447 }
4448 if (detect_input_pending ())
4449 active = MsgWaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE,
4450 QS_ALLINPUT);
4451 else
4452 active = WaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE);
4453 if (active == WAIT_OBJECT_0)
4454 { /* User pressed C-g, cancel write, then leave. Don't bother
4455 cleaning up as we may only get stuck in buggy drivers. */
4456 PurgeComm (hnd, PURGE_TXABORT | PURGE_TXCLEAR);
4457 CancelIo (hnd);
4458 errno = EIO;
4459 return -1;
4460 }
4461 if (active == WAIT_OBJECT_0 + 1
4462 && !GetOverlappedResult (hnd, ovl, (DWORD*) &nchars, TRUE))
4463 {
4464 errno = EIO;
4465 return -1;
4466 }
4467 }
4468 }
4469 else
4470 #ifdef HAVE_SOCKETS
4471 if (fd < MAXDESC && fd_info[fd].flags & FILE_SOCKET)
4472 {
4473 unsigned long nblock = 0;
4474 if (winsock_lib == NULL) abort ();
4475
4476 /* TODO: implement select() properly so non-blocking I/O works. */
4477 /* For now, make sure the write blocks. */
4478 if (fd_info[fd].flags & FILE_NDELAY)
4479 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
4480
4481 nchars = pfn_send (SOCK_HANDLE (fd), buffer, count, 0);
4482
4483 /* Set the socket back to non-blocking if it was before,
4484 for other operations that support it. */
4485 if (fd_info[fd].flags & FILE_NDELAY)
4486 {
4487 nblock = 1;
4488 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
4489 }
4490
4491 if (nchars == SOCKET_ERROR)
4492 {
4493 DebPrint(("sys_write.send failed with error %d on socket %ld\n",
4494 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
4495 set_errno ();
4496 }
4497 }
4498 else
4499 #endif
4500 nchars = _write (fd, buffer, count);
4501
4502 return nchars;
4503 }
4504
4505 static void
4506 check_windows_init_file ()
4507 {
4508 extern int noninteractive, inhibit_window_system;
4509
4510 /* A common indication that Emacs is not installed properly is when
4511 it cannot find the Windows installation file. If this file does
4512 not exist in the expected place, tell the user. */
4513
4514 if (!noninteractive && !inhibit_window_system)
4515 {
4516 extern Lisp_Object Vwindow_system, Vload_path, Qfile_exists_p;
4517 Lisp_Object objs[2];
4518 Lisp_Object full_load_path;
4519 Lisp_Object init_file;
4520 int fd;
4521
4522 objs[0] = Vload_path;
4523 objs[1] = decode_env_path (0, (getenv ("EMACSLOADPATH")));
4524 full_load_path = Fappend (2, objs);
4525 init_file = build_string ("term/w32-win");
4526 fd = openp (full_load_path, init_file, Fget_load_suffixes (), NULL, Qnil);
4527 if (fd < 0)
4528 {
4529 Lisp_Object load_path_print = Fprin1_to_string (full_load_path, Qnil);
4530 char *init_file_name = SDATA (init_file);
4531 char *load_path = SDATA (load_path_print);
4532 char *buffer = alloca (1024
4533 + strlen (init_file_name)
4534 + strlen (load_path));
4535
4536 sprintf (buffer,
4537 "The Emacs Windows initialization file \"%s.el\" "
4538 "could not be found in your Emacs installation. "
4539 "Emacs checked the following directories for this file:\n"
4540 "\n%s\n\n"
4541 "When Emacs cannot find this file, it usually means that it "
4542 "was not installed properly, or its distribution file was "
4543 "not unpacked properly.\nSee the README.W32 file in the "
4544 "top-level Emacs directory for more information.",
4545 init_file_name, load_path);
4546 MessageBox (NULL,
4547 buffer,
4548 "Emacs Abort Dialog",
4549 MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
4550 /* Use the low-level Emacs abort. */
4551 #undef abort
4552 abort ();
4553 }
4554 else
4555 {
4556 _close (fd);
4557 }
4558 }
4559 }
4560
4561 void
4562 term_ntproc ()
4563 {
4564 #ifdef HAVE_SOCKETS
4565 /* shutdown the socket interface if necessary */
4566 term_winsock ();
4567 #endif
4568
4569 term_w32select ();
4570 }
4571
4572 void
4573 init_ntproc ()
4574 {
4575 #ifdef HAVE_SOCKETS
4576 /* Initialise the socket interface now if available and requested by
4577 the user by defining PRELOAD_WINSOCK; otherwise loading will be
4578 delayed until open-network-stream is called (w32-has-winsock can
4579 also be used to dynamically load or reload winsock).
4580
4581 Conveniently, init_environment is called before us, so
4582 PRELOAD_WINSOCK can be set in the registry. */
4583
4584 /* Always initialize this correctly. */
4585 winsock_lib = NULL;
4586
4587 if (getenv ("PRELOAD_WINSOCK") != NULL)
4588 init_winsock (TRUE);
4589 #endif
4590
4591 /* Initial preparation for subprocess support: replace our standard
4592 handles with non-inheritable versions. */
4593 {
4594 HANDLE parent;
4595 HANDLE stdin_save = INVALID_HANDLE_VALUE;
4596 HANDLE stdout_save = INVALID_HANDLE_VALUE;
4597 HANDLE stderr_save = INVALID_HANDLE_VALUE;
4598
4599 parent = GetCurrentProcess ();
4600
4601 /* ignore errors when duplicating and closing; typically the
4602 handles will be invalid when running as a gui program. */
4603 DuplicateHandle (parent,
4604 GetStdHandle (STD_INPUT_HANDLE),
4605 parent,
4606 &stdin_save,
4607 0,
4608 FALSE,
4609 DUPLICATE_SAME_ACCESS);
4610
4611 DuplicateHandle (parent,
4612 GetStdHandle (STD_OUTPUT_HANDLE),
4613 parent,
4614 &stdout_save,
4615 0,
4616 FALSE,
4617 DUPLICATE_SAME_ACCESS);
4618
4619 DuplicateHandle (parent,
4620 GetStdHandle (STD_ERROR_HANDLE),
4621 parent,
4622 &stderr_save,
4623 0,
4624 FALSE,
4625 DUPLICATE_SAME_ACCESS);
4626
4627 fclose (stdin);
4628 fclose (stdout);
4629 fclose (stderr);
4630
4631 if (stdin_save != INVALID_HANDLE_VALUE)
4632 _open_osfhandle ((long) stdin_save, O_TEXT);
4633 else
4634 _open ("nul", O_TEXT | O_NOINHERIT | O_RDONLY);
4635 _fdopen (0, "r");
4636
4637 if (stdout_save != INVALID_HANDLE_VALUE)
4638 _open_osfhandle ((long) stdout_save, O_TEXT);
4639 else
4640 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
4641 _fdopen (1, "w");
4642
4643 if (stderr_save != INVALID_HANDLE_VALUE)
4644 _open_osfhandle ((long) stderr_save, O_TEXT);
4645 else
4646 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
4647 _fdopen (2, "w");
4648 }
4649
4650 /* unfortunately, atexit depends on implementation of malloc */
4651 /* atexit (term_ntproc); */
4652 signal (SIGABRT, term_ntproc);
4653
4654 /* determine which drives are fixed, for GetCachedVolumeInformation */
4655 {
4656 /* GetDriveType must have trailing backslash. */
4657 char drive[] = "A:\\";
4658
4659 /* Loop over all possible drive letters */
4660 while (*drive <= 'Z')
4661 {
4662 /* Record if this drive letter refers to a fixed drive. */
4663 fixed_drives[DRIVE_INDEX (*drive)] =
4664 (GetDriveType (drive) == DRIVE_FIXED);
4665
4666 (*drive)++;
4667 }
4668
4669 /* Reset the volume info cache. */
4670 volume_cache = NULL;
4671 }
4672
4673 /* Check to see if Emacs has been installed correctly. */
4674 check_windows_init_file ();
4675 }
4676
4677 /*
4678 shutdown_handler ensures that buffers' autosave files are
4679 up to date when the user logs off, or the system shuts down.
4680 */
4681 BOOL WINAPI shutdown_handler(DWORD type)
4682 {
4683 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
4684 if (type == CTRL_CLOSE_EVENT /* User closes console window. */
4685 || type == CTRL_LOGOFF_EVENT /* User logs off. */
4686 || type == CTRL_SHUTDOWN_EVENT) /* User shutsdown. */
4687 {
4688 /* Shut down cleanly, making sure autosave files are up to date. */
4689 shut_down_emacs (0, 0, Qnil);
4690 }
4691
4692 /* Allow other handlers to handle this signal. */
4693 return FALSE;
4694 }
4695
4696 /*
4697 globals_of_w32 is used to initialize those global variables that
4698 must always be initialized on startup even when the global variable
4699 initialized is non zero (see the function main in emacs.c).
4700 */
4701 void
4702 globals_of_w32 ()
4703 {
4704 HMODULE kernel32 = GetModuleHandle ("kernel32.dll");
4705
4706 get_process_times_fn = (GetProcessTimes_Proc)
4707 GetProcAddress (kernel32, "GetProcessTimes");
4708
4709 g_b_init_is_windows_9x = 0;
4710 g_b_init_open_process_token = 0;
4711 g_b_init_get_token_information = 0;
4712 g_b_init_lookup_account_sid = 0;
4713 g_b_init_get_sid_identifier_authority = 0;
4714 g_b_init_get_sid_sub_authority = 0;
4715 g_b_init_get_sid_sub_authority_count = 0;
4716 g_b_init_get_file_security = 0;
4717 g_b_init_get_security_descriptor_owner = 0;
4718 g_b_init_get_security_descriptor_group = 0;
4719 g_b_init_is_valid_sid = 0;
4720 /* The following sets a handler for shutdown notifications for
4721 console apps. This actually applies to Emacs in both console and
4722 GUI modes, since we had to fool windows into thinking emacs is a
4723 console application to get console mode to work. */
4724 SetConsoleCtrlHandler(shutdown_handler, TRUE);
4725
4726 /* "None" is the default group name on standalone workstations. */
4727 strcpy (dflt_group_name, "None");
4728 }
4729
4730 /* For make-serial-process */
4731 int serial_open (char *port)
4732 {
4733 HANDLE hnd;
4734 child_process *cp;
4735 int fd = -1;
4736
4737 hnd = CreateFile (port, GENERIC_READ | GENERIC_WRITE, 0, 0,
4738 OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
4739 if (hnd == INVALID_HANDLE_VALUE)
4740 error ("Could not open %s", port);
4741 fd = (int) _open_osfhandle ((int) hnd, 0);
4742 if (fd == -1)
4743 error ("Could not open %s", port);
4744
4745 cp = new_child ();
4746 if (!cp)
4747 error ("Could not create child process");
4748 cp->fd = fd;
4749 cp->status = STATUS_READ_ACKNOWLEDGED;
4750 fd_info[ fd ].hnd = hnd;
4751 fd_info[ fd ].flags |=
4752 FILE_READ | FILE_WRITE | FILE_BINARY | FILE_SERIAL;
4753 if (fd_info[ fd ].cp != NULL)
4754 {
4755 error ("fd_info[fd = %d] is already in use", fd);
4756 }
4757 fd_info[ fd ].cp = cp;
4758 cp->ovl_read.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
4759 if (cp->ovl_read.hEvent == NULL)
4760 error ("Could not create read event");
4761 cp->ovl_write.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
4762 if (cp->ovl_write.hEvent == NULL)
4763 error ("Could not create write event");
4764
4765 return fd;
4766 }
4767
4768 /* For serial-process-configure */
4769 void
4770 serial_configure (struct Lisp_Process *p,
4771 Lisp_Object contact)
4772 {
4773 Lisp_Object childp2 = Qnil;
4774 Lisp_Object tem = Qnil;
4775 HANDLE hnd;
4776 DCB dcb;
4777 COMMTIMEOUTS ct;
4778 char summary[4] = "???"; /* This usually becomes "8N1". */
4779
4780 if ((fd_info[ p->outfd ].flags & FILE_SERIAL) == 0)
4781 error ("Not a serial process");
4782 hnd = fd_info[ p->outfd ].hnd;
4783
4784 childp2 = Fcopy_sequence (p->childp);
4785
4786 /* Initialize timeouts for blocking read and blocking write. */
4787 if (!GetCommTimeouts (hnd, &ct))
4788 error ("GetCommTimeouts() failed");
4789 ct.ReadIntervalTimeout = 0;
4790 ct.ReadTotalTimeoutMultiplier = 0;
4791 ct.ReadTotalTimeoutConstant = 0;
4792 ct.WriteTotalTimeoutMultiplier = 0;
4793 ct.WriteTotalTimeoutConstant = 0;
4794 if (!SetCommTimeouts (hnd, &ct))
4795 error ("SetCommTimeouts() failed");
4796 /* Read port attributes and prepare default configuration. */
4797 memset (&dcb, 0, sizeof (dcb));
4798 dcb.DCBlength = sizeof (DCB);
4799 if (!GetCommState (hnd, &dcb))
4800 error ("GetCommState() failed");
4801 dcb.fBinary = TRUE;
4802 dcb.fNull = FALSE;
4803 dcb.fAbortOnError = FALSE;
4804 /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
4805 dcb.ErrorChar = 0;
4806 dcb.EofChar = 0;
4807 dcb.EvtChar = 0;
4808
4809 /* Configure speed. */
4810 if (!NILP (Fplist_member (contact, QCspeed)))
4811 tem = Fplist_get (contact, QCspeed);
4812 else
4813 tem = Fplist_get (p->childp, QCspeed);
4814 CHECK_NUMBER (tem);
4815 dcb.BaudRate = XINT (tem);
4816 childp2 = Fplist_put (childp2, QCspeed, tem);
4817
4818 /* Configure bytesize. */
4819 if (!NILP (Fplist_member (contact, QCbytesize)))
4820 tem = Fplist_get (contact, QCbytesize);
4821 else
4822 tem = Fplist_get (p->childp, QCbytesize);
4823 if (NILP (tem))
4824 tem = make_number (8);
4825 CHECK_NUMBER (tem);
4826 if (XINT (tem) != 7 && XINT (tem) != 8)
4827 error (":bytesize must be nil (8), 7, or 8");
4828 dcb.ByteSize = XINT (tem);
4829 summary[0] = XINT (tem) + '0';
4830 childp2 = Fplist_put (childp2, QCbytesize, tem);
4831
4832 /* Configure parity. */
4833 if (!NILP (Fplist_member (contact, QCparity)))
4834 tem = Fplist_get (contact, QCparity);
4835 else
4836 tem = Fplist_get (p->childp, QCparity);
4837 if (!NILP (tem) && !EQ (tem, Qeven) && !EQ (tem, Qodd))
4838 error (":parity must be nil (no parity), `even', or `odd'");
4839 dcb.fParity = FALSE;
4840 dcb.Parity = NOPARITY;
4841 dcb.fErrorChar = FALSE;
4842 if (NILP (tem))
4843 {
4844 summary[1] = 'N';
4845 }
4846 else if (EQ (tem, Qeven))
4847 {
4848 summary[1] = 'E';
4849 dcb.fParity = TRUE;
4850 dcb.Parity = EVENPARITY;
4851 dcb.fErrorChar = TRUE;
4852 }
4853 else if (EQ (tem, Qodd))
4854 {
4855 summary[1] = 'O';
4856 dcb.fParity = TRUE;
4857 dcb.Parity = ODDPARITY;
4858 dcb.fErrorChar = TRUE;
4859 }
4860 childp2 = Fplist_put (childp2, QCparity, tem);
4861
4862 /* Configure stopbits. */
4863 if (!NILP (Fplist_member (contact, QCstopbits)))
4864 tem = Fplist_get (contact, QCstopbits);
4865 else
4866 tem = Fplist_get (p->childp, QCstopbits);
4867 if (NILP (tem))
4868 tem = make_number (1);
4869 CHECK_NUMBER (tem);
4870 if (XINT (tem) != 1 && XINT (tem) != 2)
4871 error (":stopbits must be nil (1 stopbit), 1, or 2");
4872 summary[2] = XINT (tem) + '0';
4873 if (XINT (tem) == 1)
4874 dcb.StopBits = ONESTOPBIT;
4875 else if (XINT (tem) == 2)
4876 dcb.StopBits = TWOSTOPBITS;
4877 childp2 = Fplist_put (childp2, QCstopbits, tem);
4878
4879 /* Configure flowcontrol. */
4880 if (!NILP (Fplist_member (contact, QCflowcontrol)))
4881 tem = Fplist_get (contact, QCflowcontrol);
4882 else
4883 tem = Fplist_get (p->childp, QCflowcontrol);
4884 if (!NILP (tem) && !EQ (tem, Qhw) && !EQ (tem, Qsw))
4885 error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
4886 dcb.fOutxCtsFlow = FALSE;
4887 dcb.fOutxDsrFlow = FALSE;
4888 dcb.fDtrControl = DTR_CONTROL_DISABLE;
4889 dcb.fDsrSensitivity = FALSE;
4890 dcb.fTXContinueOnXoff = FALSE;
4891 dcb.fOutX = FALSE;
4892 dcb.fInX = FALSE;
4893 dcb.fRtsControl = RTS_CONTROL_DISABLE;
4894 dcb.XonChar = 17; /* Control-Q */
4895 dcb.XoffChar = 19; /* Control-S */
4896 if (NILP (tem))
4897 {
4898 /* Already configured. */
4899 }
4900 else if (EQ (tem, Qhw))
4901 {
4902 dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
4903 dcb.fOutxCtsFlow = TRUE;
4904 }
4905 else if (EQ (tem, Qsw))
4906 {
4907 dcb.fOutX = TRUE;
4908 dcb.fInX = TRUE;
4909 }
4910 childp2 = Fplist_put (childp2, QCflowcontrol, tem);
4911
4912 /* Activate configuration. */
4913 if (!SetCommState (hnd, &dcb))
4914 error ("SetCommState() failed");
4915
4916 childp2 = Fplist_put (childp2, QCsummary, build_string (summary));
4917 p->childp = childp2;
4918 }
4919
4920 /* end of w32.c */
4921
4922 /* arch-tag: 90442dd3-37be-482b-b272-ac752e3049f1
4923 (do not change this comment) */