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