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