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