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