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