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