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