]> code.delx.au - gnu-emacs/blob - src/w32.c
Merge changes from emacs-23 branch
[gnu-emacs] / src / w32.c
1 /* Utility and Unix shadow routines for GNU Emacs on the Microsoft W32 API.
2 Copyright (C) 1994, 1995, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
3 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
4
5 This file is part of GNU Emacs.
6
7 GNU Emacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
19
20 /*
21 Geoff Voelker (voelker@cs.washington.edu) 7-29-94
22 */
23 #include <stddef.h> /* for offsetof */
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <float.h> /* for DBL_EPSILON */
27 #include <io.h>
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <ctype.h>
31 #include <signal.h>
32 #include <sys/file.h>
33 #include <sys/time.h>
34 #include <sys/utime.h>
35 #include <mbstring.h> /* for _mbspbrk */
36 #include <math.h>
37 #include <setjmp.h>
38
39 /* must include CRT headers *before* config.h */
40
41 #ifdef HAVE_CONFIG_H
42 #include <config.h>
43 #endif
44
45 #undef access
46 #undef chdir
47 #undef chmod
48 #undef creat
49 #undef ctime
50 #undef fopen
51 #undef link
52 #undef mkdir
53 #undef mktemp
54 #undef open
55 #undef rename
56 #undef rmdir
57 #undef unlink
58
59 #undef close
60 #undef dup
61 #undef dup2
62 #undef pipe
63 #undef read
64 #undef write
65
66 #undef strerror
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 suplied 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 /* For serial_configure and serial_open. */
145 #include "process.h"
146
147 typedef HRESULT (WINAPI * ShGetFolderPath_fn)
148 (IN HWND, IN int, IN HANDLE, IN DWORD, OUT char *);
149
150 void globals_of_w32 (void);
151 static DWORD get_rid (PSID);
152
153 extern Lisp_Object Vw32_downcase_file_names;
154 extern Lisp_Object Vw32_generate_fake_inodes;
155 extern Lisp_Object Vw32_get_true_file_attributes;
156 /* Defined in process.c for its own purpose. */
157 extern Lisp_Object Qlocal;
158
159 extern int w32_num_mouse_buttons;
160
161 \f
162 /* Initialization states.
163
164 WARNING: If you add any more such variables for additional APIs,
165 you MUST add initialization for them to globals_of_w32
166 below. This is because these variables might get set
167 to non-NULL values during dumping, but the dumped Emacs
168 cannot reuse those values, because it could be run on a
169 different version of the OS, where API addresses are
170 different. */
171 static BOOL g_b_init_is_windows_9x;
172 static BOOL g_b_init_open_process_token;
173 static BOOL g_b_init_get_token_information;
174 static BOOL g_b_init_lookup_account_sid;
175 static BOOL g_b_init_get_sid_sub_authority;
176 static BOOL g_b_init_get_sid_sub_authority_count;
177 static BOOL g_b_init_get_file_security;
178 static BOOL g_b_init_get_security_descriptor_owner;
179 static BOOL g_b_init_get_security_descriptor_group;
180 static BOOL g_b_init_is_valid_sid;
181 static BOOL g_b_init_create_toolhelp32_snapshot;
182 static BOOL g_b_init_process32_first;
183 static BOOL g_b_init_process32_next;
184 static BOOL g_b_init_open_thread_token;
185 static BOOL g_b_init_impersonate_self;
186 static BOOL g_b_init_revert_to_self;
187 static BOOL g_b_init_get_process_memory_info;
188 static BOOL g_b_init_get_process_working_set_size;
189 static BOOL g_b_init_global_memory_status;
190 static BOOL g_b_init_global_memory_status_ex;
191 static BOOL g_b_init_get_length_sid;
192 static BOOL g_b_init_equal_sid;
193 static BOOL g_b_init_copy_sid;
194 static BOOL g_b_init_get_native_system_info;
195 static BOOL g_b_init_get_system_times;
196
197 /*
198 BEGIN: Wrapper functions around OpenProcessToken
199 and other functions in advapi32.dll that are only
200 supported in Windows NT / 2k / XP
201 */
202 /* ** Function pointer typedefs ** */
203 typedef BOOL (WINAPI * OpenProcessToken_Proc) (
204 HANDLE ProcessHandle,
205 DWORD DesiredAccess,
206 PHANDLE TokenHandle);
207 typedef BOOL (WINAPI * GetTokenInformation_Proc) (
208 HANDLE TokenHandle,
209 TOKEN_INFORMATION_CLASS TokenInformationClass,
210 LPVOID TokenInformation,
211 DWORD TokenInformationLength,
212 PDWORD ReturnLength);
213 typedef BOOL (WINAPI * GetProcessTimes_Proc) (
214 HANDLE process_handle,
215 LPFILETIME creation_time,
216 LPFILETIME exit_time,
217 LPFILETIME kernel_time,
218 LPFILETIME user_time);
219
220 GetProcessTimes_Proc get_process_times_fn = NULL;
221
222 #ifdef _UNICODE
223 const char * const LookupAccountSid_Name = "LookupAccountSidW";
224 const char * const GetFileSecurity_Name = "GetFileSecurityW";
225 #else
226 const char * const LookupAccountSid_Name = "LookupAccountSidA";
227 const char * const GetFileSecurity_Name = "GetFileSecurityA";
228 #endif
229 typedef BOOL (WINAPI * LookupAccountSid_Proc) (
230 LPCTSTR lpSystemName,
231 PSID Sid,
232 LPTSTR Name,
233 LPDWORD cbName,
234 LPTSTR DomainName,
235 LPDWORD cbDomainName,
236 PSID_NAME_USE peUse);
237 typedef PDWORD (WINAPI * GetSidSubAuthority_Proc) (
238 PSID pSid,
239 DWORD n);
240 typedef PUCHAR (WINAPI * GetSidSubAuthorityCount_Proc) (
241 PSID pSid);
242 typedef BOOL (WINAPI * GetFileSecurity_Proc) (
243 LPCTSTR lpFileName,
244 SECURITY_INFORMATION RequestedInformation,
245 PSECURITY_DESCRIPTOR pSecurityDescriptor,
246 DWORD nLength,
247 LPDWORD lpnLengthNeeded);
248 typedef BOOL (WINAPI * GetSecurityDescriptorOwner_Proc) (
249 PSECURITY_DESCRIPTOR pSecurityDescriptor,
250 PSID *pOwner,
251 LPBOOL lpbOwnerDefaulted);
252 typedef BOOL (WINAPI * GetSecurityDescriptorGroup_Proc) (
253 PSECURITY_DESCRIPTOR pSecurityDescriptor,
254 PSID *pGroup,
255 LPBOOL lpbGroupDefaulted);
256 typedef BOOL (WINAPI * IsValidSid_Proc) (
257 PSID sid);
258 typedef HANDLE (WINAPI * CreateToolhelp32Snapshot_Proc) (
259 DWORD dwFlags,
260 DWORD th32ProcessID);
261 typedef BOOL (WINAPI * Process32First_Proc) (
262 HANDLE hSnapshot,
263 LPPROCESSENTRY32 lppe);
264 typedef BOOL (WINAPI * Process32Next_Proc) (
265 HANDLE hSnapshot,
266 LPPROCESSENTRY32 lppe);
267 typedef BOOL (WINAPI * OpenThreadToken_Proc) (
268 HANDLE ThreadHandle,
269 DWORD DesiredAccess,
270 BOOL OpenAsSelf,
271 PHANDLE TokenHandle);
272 typedef BOOL (WINAPI * ImpersonateSelf_Proc) (
273 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel);
274 typedef BOOL (WINAPI * RevertToSelf_Proc) (void);
275 typedef BOOL (WINAPI * GetProcessMemoryInfo_Proc) (
276 HANDLE Process,
277 PPROCESS_MEMORY_COUNTERS ppsmemCounters,
278 DWORD cb);
279 typedef BOOL (WINAPI * GetProcessWorkingSetSize_Proc) (
280 HANDLE hProcess,
281 DWORD * lpMinimumWorkingSetSize,
282 DWORD * lpMaximumWorkingSetSize);
283 typedef BOOL (WINAPI * GlobalMemoryStatus_Proc) (
284 LPMEMORYSTATUS lpBuffer);
285 typedef BOOL (WINAPI * GlobalMemoryStatusEx_Proc) (
286 LPMEMORY_STATUS_EX lpBuffer);
287 typedef BOOL (WINAPI * CopySid_Proc) (
288 DWORD nDestinationSidLength,
289 PSID pDestinationSid,
290 PSID pSourceSid);
291 typedef BOOL (WINAPI * EqualSid_Proc) (
292 PSID pSid1,
293 PSID pSid2);
294 typedef DWORD (WINAPI * GetLengthSid_Proc) (
295 PSID pSid);
296 typedef void (WINAPI * GetNativeSystemInfo_Proc) (
297 LPSYSTEM_INFO lpSystemInfo);
298 typedef BOOL (WINAPI * GetSystemTimes_Proc) (
299 LPFILETIME lpIdleTime,
300 LPFILETIME lpKernelTime,
301 LPFILETIME lpUserTime);
302
303 /* ** A utility function ** */
304 static BOOL
305 is_windows_9x (void)
306 {
307 static BOOL s_b_ret = 0;
308 OSVERSIONINFO os_ver;
309 if (g_b_init_is_windows_9x == 0)
310 {
311 g_b_init_is_windows_9x = 1;
312 ZeroMemory (&os_ver, sizeof (OSVERSIONINFO));
313 os_ver.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
314 if (GetVersionEx (&os_ver))
315 {
316 s_b_ret = (os_ver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
317 }
318 }
319 return s_b_ret;
320 }
321
322 /* Get total user and system times for get-internal-run-time.
323 Returns a list of three integers if the times are provided by the OS
324 (NT derivatives), otherwise it returns the result of current-time. */
325 Lisp_Object
326 w32_get_internal_run_time (void)
327 {
328 if (get_process_times_fn)
329 {
330 FILETIME create, exit, kernel, user;
331 HANDLE proc = GetCurrentProcess ();
332 if ((*get_process_times_fn) (proc, &create, &exit, &kernel, &user))
333 {
334 LARGE_INTEGER user_int, kernel_int, total;
335 int microseconds;
336 user_int.LowPart = user.dwLowDateTime;
337 user_int.HighPart = user.dwHighDateTime;
338 kernel_int.LowPart = kernel.dwLowDateTime;
339 kernel_int.HighPart = kernel.dwHighDateTime;
340 total.QuadPart = user_int.QuadPart + kernel_int.QuadPart;
341 /* FILETIME is 100 nanosecond increments, Emacs only wants
342 microsecond resolution. */
343 total.QuadPart /= 10;
344 microseconds = total.QuadPart % 1000000;
345 total.QuadPart /= 1000000;
346
347 /* Sanity check to make sure we can represent the result. */
348 if (total.HighPart == 0)
349 {
350 int secs = total.LowPart;
351
352 return list3 (make_number ((secs >> 16) & 0xffff),
353 make_number (secs & 0xffff),
354 make_number (microseconds));
355 }
356 }
357 }
358
359 return Fcurrent_time ();
360 }
361
362 /* ** The wrapper functions ** */
363
364 static BOOL WINAPI
365 open_process_token (HANDLE ProcessHandle,
366 DWORD DesiredAccess,
367 PHANDLE TokenHandle)
368 {
369 static OpenProcessToken_Proc s_pfn_Open_Process_Token = NULL;
370 HMODULE hm_advapi32 = NULL;
371 if (is_windows_9x () == TRUE)
372 {
373 return FALSE;
374 }
375 if (g_b_init_open_process_token == 0)
376 {
377 g_b_init_open_process_token = 1;
378 hm_advapi32 = LoadLibrary ("Advapi32.dll");
379 s_pfn_Open_Process_Token =
380 (OpenProcessToken_Proc) GetProcAddress (hm_advapi32, "OpenProcessToken");
381 }
382 if (s_pfn_Open_Process_Token == NULL)
383 {
384 return FALSE;
385 }
386 return (
387 s_pfn_Open_Process_Token (
388 ProcessHandle,
389 DesiredAccess,
390 TokenHandle)
391 );
392 }
393
394 static BOOL WINAPI
395 get_token_information (HANDLE TokenHandle,
396 TOKEN_INFORMATION_CLASS TokenInformationClass,
397 LPVOID TokenInformation,
398 DWORD TokenInformationLength,
399 PDWORD ReturnLength)
400 {
401 static GetTokenInformation_Proc s_pfn_Get_Token_Information = NULL;
402 HMODULE hm_advapi32 = NULL;
403 if (is_windows_9x () == TRUE)
404 {
405 return FALSE;
406 }
407 if (g_b_init_get_token_information == 0)
408 {
409 g_b_init_get_token_information = 1;
410 hm_advapi32 = LoadLibrary ("Advapi32.dll");
411 s_pfn_Get_Token_Information =
412 (GetTokenInformation_Proc) GetProcAddress (hm_advapi32, "GetTokenInformation");
413 }
414 if (s_pfn_Get_Token_Information == NULL)
415 {
416 return FALSE;
417 }
418 return (
419 s_pfn_Get_Token_Information (
420 TokenHandle,
421 TokenInformationClass,
422 TokenInformation,
423 TokenInformationLength,
424 ReturnLength)
425 );
426 }
427
428 static BOOL WINAPI
429 lookup_account_sid (LPCTSTR lpSystemName,
430 PSID Sid,
431 LPTSTR Name,
432 LPDWORD cbName,
433 LPTSTR DomainName,
434 LPDWORD cbDomainName,
435 PSID_NAME_USE peUse)
436 {
437 static LookupAccountSid_Proc s_pfn_Lookup_Account_Sid = NULL;
438 HMODULE hm_advapi32 = NULL;
439 if (is_windows_9x () == TRUE)
440 {
441 return FALSE;
442 }
443 if (g_b_init_lookup_account_sid == 0)
444 {
445 g_b_init_lookup_account_sid = 1;
446 hm_advapi32 = LoadLibrary ("Advapi32.dll");
447 s_pfn_Lookup_Account_Sid =
448 (LookupAccountSid_Proc) GetProcAddress (hm_advapi32, LookupAccountSid_Name);
449 }
450 if (s_pfn_Lookup_Account_Sid == NULL)
451 {
452 return FALSE;
453 }
454 return (
455 s_pfn_Lookup_Account_Sid (
456 lpSystemName,
457 Sid,
458 Name,
459 cbName,
460 DomainName,
461 cbDomainName,
462 peUse)
463 );
464 }
465
466 static PDWORD WINAPI
467 get_sid_sub_authority (PSID pSid, DWORD n)
468 {
469 static GetSidSubAuthority_Proc s_pfn_Get_Sid_Sub_Authority = NULL;
470 static DWORD zero = 0U;
471 HMODULE hm_advapi32 = NULL;
472 if (is_windows_9x () == TRUE)
473 {
474 return &zero;
475 }
476 if (g_b_init_get_sid_sub_authority == 0)
477 {
478 g_b_init_get_sid_sub_authority = 1;
479 hm_advapi32 = LoadLibrary ("Advapi32.dll");
480 s_pfn_Get_Sid_Sub_Authority =
481 (GetSidSubAuthority_Proc) GetProcAddress (
482 hm_advapi32, "GetSidSubAuthority");
483 }
484 if (s_pfn_Get_Sid_Sub_Authority == NULL)
485 {
486 return &zero;
487 }
488 return (s_pfn_Get_Sid_Sub_Authority (pSid, n));
489 }
490
491 static PUCHAR WINAPI
492 get_sid_sub_authority_count (PSID pSid)
493 {
494 static GetSidSubAuthorityCount_Proc s_pfn_Get_Sid_Sub_Authority_Count = NULL;
495 static UCHAR zero = 0U;
496 HMODULE hm_advapi32 = NULL;
497 if (is_windows_9x () == TRUE)
498 {
499 return &zero;
500 }
501 if (g_b_init_get_sid_sub_authority_count == 0)
502 {
503 g_b_init_get_sid_sub_authority_count = 1;
504 hm_advapi32 = LoadLibrary ("Advapi32.dll");
505 s_pfn_Get_Sid_Sub_Authority_Count =
506 (GetSidSubAuthorityCount_Proc) GetProcAddress (
507 hm_advapi32, "GetSidSubAuthorityCount");
508 }
509 if (s_pfn_Get_Sid_Sub_Authority_Count == NULL)
510 {
511 return &zero;
512 }
513 return (s_pfn_Get_Sid_Sub_Authority_Count (pSid));
514 }
515
516 static BOOL WINAPI
517 get_file_security (LPCTSTR lpFileName,
518 SECURITY_INFORMATION RequestedInformation,
519 PSECURITY_DESCRIPTOR pSecurityDescriptor,
520 DWORD nLength,
521 LPDWORD lpnLengthNeeded)
522 {
523 static GetFileSecurity_Proc s_pfn_Get_File_Security = NULL;
524 HMODULE hm_advapi32 = NULL;
525 if (is_windows_9x () == TRUE)
526 {
527 return FALSE;
528 }
529 if (g_b_init_get_file_security == 0)
530 {
531 g_b_init_get_file_security = 1;
532 hm_advapi32 = LoadLibrary ("Advapi32.dll");
533 s_pfn_Get_File_Security =
534 (GetFileSecurity_Proc) GetProcAddress (
535 hm_advapi32, GetFileSecurity_Name);
536 }
537 if (s_pfn_Get_File_Security == NULL)
538 {
539 return FALSE;
540 }
541 return (s_pfn_Get_File_Security (lpFileName, RequestedInformation,
542 pSecurityDescriptor, nLength,
543 lpnLengthNeeded));
544 }
545
546 static BOOL WINAPI
547 get_security_descriptor_owner (PSECURITY_DESCRIPTOR pSecurityDescriptor,
548 PSID *pOwner,
549 LPBOOL lpbOwnerDefaulted)
550 {
551 static GetSecurityDescriptorOwner_Proc s_pfn_Get_Security_Descriptor_Owner = NULL;
552 HMODULE hm_advapi32 = NULL;
553 if (is_windows_9x () == TRUE)
554 {
555 return FALSE;
556 }
557 if (g_b_init_get_security_descriptor_owner == 0)
558 {
559 g_b_init_get_security_descriptor_owner = 1;
560 hm_advapi32 = LoadLibrary ("Advapi32.dll");
561 s_pfn_Get_Security_Descriptor_Owner =
562 (GetSecurityDescriptorOwner_Proc) GetProcAddress (
563 hm_advapi32, "GetSecurityDescriptorOwner");
564 }
565 if (s_pfn_Get_Security_Descriptor_Owner == NULL)
566 {
567 return FALSE;
568 }
569 return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor, pOwner,
570 lpbOwnerDefaulted));
571 }
572
573 static BOOL WINAPI
574 get_security_descriptor_group (PSECURITY_DESCRIPTOR pSecurityDescriptor,
575 PSID *pGroup,
576 LPBOOL lpbGroupDefaulted)
577 {
578 static GetSecurityDescriptorGroup_Proc s_pfn_Get_Security_Descriptor_Group = NULL;
579 HMODULE hm_advapi32 = NULL;
580 if (is_windows_9x () == TRUE)
581 {
582 return FALSE;
583 }
584 if (g_b_init_get_security_descriptor_group == 0)
585 {
586 g_b_init_get_security_descriptor_group = 1;
587 hm_advapi32 = LoadLibrary ("Advapi32.dll");
588 s_pfn_Get_Security_Descriptor_Group =
589 (GetSecurityDescriptorGroup_Proc) GetProcAddress (
590 hm_advapi32, "GetSecurityDescriptorGroup");
591 }
592 if (s_pfn_Get_Security_Descriptor_Group == NULL)
593 {
594 return FALSE;
595 }
596 return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor, pGroup,
597 lpbGroupDefaulted));
598 }
599
600 static BOOL WINAPI
601 is_valid_sid (PSID sid)
602 {
603 static IsValidSid_Proc s_pfn_Is_Valid_Sid = NULL;
604 HMODULE hm_advapi32 = NULL;
605 if (is_windows_9x () == TRUE)
606 {
607 return FALSE;
608 }
609 if (g_b_init_is_valid_sid == 0)
610 {
611 g_b_init_is_valid_sid = 1;
612 hm_advapi32 = LoadLibrary ("Advapi32.dll");
613 s_pfn_Is_Valid_Sid =
614 (IsValidSid_Proc) GetProcAddress (
615 hm_advapi32, "IsValidSid");
616 }
617 if (s_pfn_Is_Valid_Sid == NULL)
618 {
619 return FALSE;
620 }
621 return (s_pfn_Is_Valid_Sid (sid));
622 }
623
624 static BOOL WINAPI
625 equal_sid (PSID sid1, PSID sid2)
626 {
627 static EqualSid_Proc s_pfn_Equal_Sid = NULL;
628 HMODULE hm_advapi32 = NULL;
629 if (is_windows_9x () == TRUE)
630 {
631 return FALSE;
632 }
633 if (g_b_init_equal_sid == 0)
634 {
635 g_b_init_equal_sid = 1;
636 hm_advapi32 = LoadLibrary ("Advapi32.dll");
637 s_pfn_Equal_Sid =
638 (EqualSid_Proc) GetProcAddress (
639 hm_advapi32, "EqualSid");
640 }
641 if (s_pfn_Equal_Sid == NULL)
642 {
643 return FALSE;
644 }
645 return (s_pfn_Equal_Sid (sid1, sid2));
646 }
647
648 static DWORD WINAPI
649 get_length_sid (PSID sid)
650 {
651 static GetLengthSid_Proc s_pfn_Get_Length_Sid = NULL;
652 HMODULE hm_advapi32 = NULL;
653 if (is_windows_9x () == TRUE)
654 {
655 return 0;
656 }
657 if (g_b_init_get_length_sid == 0)
658 {
659 g_b_init_get_length_sid = 1;
660 hm_advapi32 = LoadLibrary ("Advapi32.dll");
661 s_pfn_Get_Length_Sid =
662 (GetLengthSid_Proc) GetProcAddress (
663 hm_advapi32, "GetLengthSid");
664 }
665 if (s_pfn_Get_Length_Sid == NULL)
666 {
667 return 0;
668 }
669 return (s_pfn_Get_Length_Sid (sid));
670 }
671
672 static BOOL WINAPI
673 copy_sid (DWORD destlen, PSID dest, PSID src)
674 {
675 static CopySid_Proc s_pfn_Copy_Sid = NULL;
676 HMODULE hm_advapi32 = NULL;
677 if (is_windows_9x () == TRUE)
678 {
679 return FALSE;
680 }
681 if (g_b_init_copy_sid == 0)
682 {
683 g_b_init_copy_sid = 1;
684 hm_advapi32 = LoadLibrary ("Advapi32.dll");
685 s_pfn_Copy_Sid =
686 (CopySid_Proc) GetProcAddress (
687 hm_advapi32, "CopySid");
688 }
689 if (s_pfn_Copy_Sid == NULL)
690 {
691 return FALSE;
692 }
693 return (s_pfn_Copy_Sid (destlen, dest, src));
694 }
695
696 /*
697 END: Wrapper functions around OpenProcessToken
698 and other functions in advapi32.dll that are only
699 supported in Windows NT / 2k / XP
700 */
701
702 static void WINAPI
703 get_native_system_info (LPSYSTEM_INFO lpSystemInfo)
704 {
705 static GetNativeSystemInfo_Proc s_pfn_Get_Native_System_Info = NULL;
706 if (is_windows_9x () != TRUE)
707 {
708 if (g_b_init_get_native_system_info == 0)
709 {
710 g_b_init_get_native_system_info = 1;
711 s_pfn_Get_Native_System_Info =
712 (GetNativeSystemInfo_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
713 "GetNativeSystemInfo");
714 }
715 if (s_pfn_Get_Native_System_Info != NULL)
716 s_pfn_Get_Native_System_Info (lpSystemInfo);
717 }
718 else
719 lpSystemInfo->dwNumberOfProcessors = -1;
720 }
721
722 static BOOL WINAPI
723 get_system_times (LPFILETIME lpIdleTime,
724 LPFILETIME lpKernelTime,
725 LPFILETIME lpUserTime)
726 {
727 static GetSystemTimes_Proc s_pfn_Get_System_times = NULL;
728 if (is_windows_9x () == TRUE)
729 {
730 return FALSE;
731 }
732 if (g_b_init_get_system_times == 0)
733 {
734 g_b_init_get_system_times = 1;
735 s_pfn_Get_System_times =
736 (GetSystemTimes_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
737 "GetSystemTimes");
738 }
739 if (s_pfn_Get_System_times == NULL)
740 return FALSE;
741 return (s_pfn_Get_System_times (lpIdleTime, lpKernelTime, lpUserTime));
742 }
743 \f
744 /* Equivalent of strerror for W32 error codes. */
745 char *
746 w32_strerror (int error_no)
747 {
748 static char buf[500];
749
750 if (error_no == 0)
751 error_no = GetLastError ();
752
753 buf[0] = '\0';
754 if (!FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL,
755 error_no,
756 0, /* choose most suitable language */
757 buf, sizeof (buf), NULL))
758 sprintf (buf, "w32 error %u", error_no);
759 return buf;
760 }
761
762 /* Return 1 if P is a valid pointer to an object of size SIZE. Return
763 0 if P is NOT a valid pointer. Return -1 if we cannot validate P.
764
765 This is called from alloc.c:valid_pointer_p. */
766 int
767 w32_valid_pointer_p (void *p, int size)
768 {
769 SIZE_T done;
770 HANDLE h = OpenProcess (PROCESS_VM_READ, FALSE, GetCurrentProcessId ());
771
772 if (h)
773 {
774 unsigned char *buf = alloca (size);
775 int retval = ReadProcessMemory (h, p, buf, size, &done);
776
777 CloseHandle (h);
778 return retval;
779 }
780 else
781 return -1;
782 }
783
784 static char startup_dir[MAXPATHLEN];
785
786 /* Get the current working directory. */
787 char *
788 getwd (char *dir)
789 {
790 #if 0
791 if (GetCurrentDirectory (MAXPATHLEN, dir) > 0)
792 return dir;
793 return NULL;
794 #else
795 /* Emacs doesn't actually change directory itself, and we want to
796 force our real wd to be where emacs.exe is to avoid unnecessary
797 conflicts when trying to rename or delete directories. */
798 strcpy (dir, startup_dir);
799 return dir;
800 #endif
801 }
802
803 /* Emulate getloadavg. */
804
805 struct load_sample {
806 time_t sample_time;
807 ULONGLONG idle;
808 ULONGLONG kernel;
809 ULONGLONG user;
810 };
811
812 /* Number of processors on this machine. */
813 static unsigned num_of_processors;
814
815 /* We maintain 1-sec samples for the last 16 minutes in a circular buffer. */
816 static struct load_sample samples[16*60];
817 static int first_idx = -1, last_idx = -1;
818 static int max_idx = sizeof (samples) / sizeof (samples[0]);
819
820 static int
821 buf_next (int from)
822 {
823 int next_idx = from + 1;
824
825 if (next_idx >= max_idx)
826 next_idx = 0;
827
828 return next_idx;
829 }
830
831 static int
832 buf_prev (int from)
833 {
834 int prev_idx = from - 1;
835
836 if (prev_idx < 0)
837 prev_idx = max_idx - 1;
838
839 return prev_idx;
840 }
841
842 static void
843 sample_system_load (ULONGLONG *idle, ULONGLONG *kernel, ULONGLONG *user)
844 {
845 SYSTEM_INFO sysinfo;
846 FILETIME ft_idle, ft_user, ft_kernel;
847
848 /* Initialize the number of processors on this machine. */
849 if (num_of_processors <= 0)
850 {
851 get_native_system_info (&sysinfo);
852 num_of_processors = sysinfo.dwNumberOfProcessors;
853 if (num_of_processors <= 0)
854 {
855 GetSystemInfo (&sysinfo);
856 num_of_processors = sysinfo.dwNumberOfProcessors;
857 }
858 if (num_of_processors <= 0)
859 num_of_processors = 1;
860 }
861
862 /* TODO: Take into account threads that are ready to run, by
863 sampling the "\System\Processor Queue Length" performance
864 counter. The code below accounts only for threads that are
865 actually running. */
866
867 if (get_system_times (&ft_idle, &ft_kernel, &ft_user))
868 {
869 ULARGE_INTEGER uidle, ukernel, uuser;
870
871 memcpy (&uidle, &ft_idle, sizeof (ft_idle));
872 memcpy (&ukernel, &ft_kernel, sizeof (ft_kernel));
873 memcpy (&uuser, &ft_user, sizeof (ft_user));
874 *idle = uidle.QuadPart;
875 *kernel = ukernel.QuadPart;
876 *user = uuser.QuadPart;
877 }
878 else
879 {
880 *idle = 0;
881 *kernel = 0;
882 *user = 0;
883 }
884 }
885
886 /* Produce the load average for a given time interval, using the
887 samples in the samples[] array. WHICH can be 0, 1, or 2, meaning
888 1-minute, 5-minute, or 15-minute average, respectively. */
889 static double
890 getavg (int which)
891 {
892 double retval = -1.0;
893 double tdiff;
894 int idx;
895 double span = (which == 0 ? 1.0 : (which == 1 ? 5.0 : 15.0)) * 60;
896 time_t now = samples[last_idx].sample_time;
897
898 if (first_idx != last_idx)
899 {
900 for (idx = buf_prev (last_idx); ; idx = buf_prev (idx))
901 {
902 tdiff = difftime (now, samples[idx].sample_time);
903 if (tdiff >= span - 2*DBL_EPSILON*now)
904 {
905 long double sys =
906 samples[last_idx].kernel + samples[last_idx].user
907 - (samples[idx].kernel + samples[idx].user);
908 long double idl = samples[last_idx].idle - samples[idx].idle;
909
910 retval = (1.0 - idl / sys) * num_of_processors;
911 break;
912 }
913 if (idx == first_idx)
914 break;
915 }
916 }
917
918 return retval;
919 }
920
921 int
922 getloadavg (double loadavg[], int nelem)
923 {
924 int elem;
925 ULONGLONG idle, kernel, user;
926 time_t now = time (NULL);
927
928 /* Store another sample. We ignore samples that are less than 1 sec
929 apart. */
930 if (difftime (now, samples[last_idx].sample_time) >= 1.0 - 2*DBL_EPSILON*now)
931 {
932 sample_system_load (&idle, &kernel, &user);
933 last_idx = buf_next (last_idx);
934 samples[last_idx].sample_time = now;
935 samples[last_idx].idle = idle;
936 samples[last_idx].kernel = kernel;
937 samples[last_idx].user = user;
938 /* If the buffer has more that 15 min worth of samples, discard
939 the old ones. */
940 if (first_idx == -1)
941 first_idx = last_idx;
942 while (first_idx != last_idx
943 && (difftime (now, samples[first_idx].sample_time)
944 >= 15.0*60 + 2*DBL_EPSILON*now))
945 first_idx = buf_next (first_idx);
946 }
947
948 for (elem = 0; elem < nelem; elem++)
949 {
950 double avg = getavg (elem);
951
952 if (avg < 0)
953 break;
954 loadavg[elem] = avg;
955 }
956
957 return elem;
958 }
959
960 /* Emulate getpwuid, getpwnam and others. */
961
962 #define PASSWD_FIELD_SIZE 256
963
964 static char dflt_passwd_name[PASSWD_FIELD_SIZE];
965 static char dflt_passwd_passwd[PASSWD_FIELD_SIZE];
966 static char dflt_passwd_gecos[PASSWD_FIELD_SIZE];
967 static char dflt_passwd_dir[PASSWD_FIELD_SIZE];
968 static char dflt_passwd_shell[PASSWD_FIELD_SIZE];
969
970 static struct passwd dflt_passwd =
971 {
972 dflt_passwd_name,
973 dflt_passwd_passwd,
974 0,
975 0,
976 0,
977 dflt_passwd_gecos,
978 dflt_passwd_dir,
979 dflt_passwd_shell,
980 };
981
982 static char dflt_group_name[GNLEN+1];
983
984 static struct group dflt_group =
985 {
986 /* When group information is not available, we return this as the
987 group for all files. */
988 dflt_group_name,
989 0,
990 };
991
992 unsigned
993 getuid (void)
994 {
995 return dflt_passwd.pw_uid;
996 }
997
998 unsigned
999 geteuid (void)
1000 {
1001 /* I could imagine arguing for checking to see whether the user is
1002 in the Administrators group and returning a UID of 0 for that
1003 case, but I don't know how wise that would be in the long run. */
1004 return getuid ();
1005 }
1006
1007 unsigned
1008 getgid (void)
1009 {
1010 return dflt_passwd.pw_gid;
1011 }
1012
1013 unsigned
1014 getegid (void)
1015 {
1016 return getgid ();
1017 }
1018
1019 struct passwd *
1020 getpwuid (unsigned uid)
1021 {
1022 if (uid == dflt_passwd.pw_uid)
1023 return &dflt_passwd;
1024 return NULL;
1025 }
1026
1027 struct group *
1028 getgrgid (gid_t gid)
1029 {
1030 return &dflt_group;
1031 }
1032
1033 struct passwd *
1034 getpwnam (char *name)
1035 {
1036 struct passwd *pw;
1037
1038 pw = getpwuid (getuid ());
1039 if (!pw)
1040 return pw;
1041
1042 if (xstrcasecmp (name, pw->pw_name))
1043 return NULL;
1044
1045 return pw;
1046 }
1047
1048 static void
1049 init_user_info (void)
1050 {
1051 /* Find the user's real name by opening the process token and
1052 looking up the name associated with the user-sid in that token.
1053
1054 Use the relative portion of the identifier authority value from
1055 the user-sid as the user id value (same for group id using the
1056 primary group sid from the process token). */
1057
1058 char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
1059 DWORD ulength = sizeof (uname), dlength = sizeof (domain), needed;
1060 DWORD glength = sizeof (gname);
1061 HANDLE token = NULL;
1062 SID_NAME_USE user_type;
1063 unsigned char *buf = NULL;
1064 DWORD blen = 0;
1065 TOKEN_USER user_token;
1066 TOKEN_PRIMARY_GROUP group_token;
1067 BOOL result;
1068
1069 result = open_process_token (GetCurrentProcess (), TOKEN_QUERY, &token);
1070 if (result)
1071 {
1072 result = get_token_information (token, TokenUser, NULL, 0, &blen);
1073 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
1074 {
1075 buf = xmalloc (blen);
1076 result = get_token_information (token, TokenUser,
1077 (LPVOID)buf, blen, &needed);
1078 if (result)
1079 {
1080 memcpy (&user_token, buf, sizeof (user_token));
1081 result = lookup_account_sid (NULL, user_token.User.Sid,
1082 uname, &ulength,
1083 domain, &dlength, &user_type);
1084 }
1085 }
1086 else
1087 result = FALSE;
1088 }
1089 if (result)
1090 {
1091 strcpy (dflt_passwd.pw_name, uname);
1092 /* Determine a reasonable uid value. */
1093 if (xstrcasecmp ("administrator", uname) == 0)
1094 {
1095 dflt_passwd.pw_uid = 500; /* well-known Administrator uid */
1096 dflt_passwd.pw_gid = 513; /* well-known None gid */
1097 }
1098 else
1099 {
1100 /* Use the last sub-authority value of the RID, the relative
1101 portion of the SID, as user/group ID. */
1102 dflt_passwd.pw_uid = get_rid (user_token.User.Sid);
1103
1104 /* Get group id and name. */
1105 result = get_token_information (token, TokenPrimaryGroup,
1106 (LPVOID)buf, blen, &needed);
1107 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
1108 {
1109 buf = xrealloc (buf, blen = needed);
1110 result = get_token_information (token, TokenPrimaryGroup,
1111 (LPVOID)buf, blen, &needed);
1112 }
1113 if (result)
1114 {
1115 memcpy (&group_token, buf, sizeof (group_token));
1116 dflt_passwd.pw_gid = get_rid (group_token.PrimaryGroup);
1117 dlength = sizeof (domain);
1118 /* If we can get at the real Primary Group name, use that.
1119 Otherwise, the default group name was already set to
1120 "None" in globals_of_w32. */
1121 if (lookup_account_sid (NULL, group_token.PrimaryGroup,
1122 gname, &glength, NULL, &dlength,
1123 &user_type))
1124 strcpy (dflt_group_name, gname);
1125 }
1126 else
1127 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
1128 }
1129 }
1130 /* If security calls are not supported (presumably because we
1131 are running under Windows 9X), fallback to this: */
1132 else if (GetUserName (uname, &ulength))
1133 {
1134 strcpy (dflt_passwd.pw_name, uname);
1135 if (xstrcasecmp ("administrator", uname) == 0)
1136 dflt_passwd.pw_uid = 0;
1137 else
1138 dflt_passwd.pw_uid = 123;
1139 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
1140 }
1141 else
1142 {
1143 strcpy (dflt_passwd.pw_name, "unknown");
1144 dflt_passwd.pw_uid = 123;
1145 dflt_passwd.pw_gid = 123;
1146 }
1147 dflt_group.gr_gid = dflt_passwd.pw_gid;
1148
1149 /* Ensure HOME and SHELL are defined. */
1150 if (getenv ("HOME") == NULL)
1151 abort ();
1152 if (getenv ("SHELL") == NULL)
1153 abort ();
1154
1155 /* Set dir and shell from environment variables. */
1156 strcpy (dflt_passwd.pw_dir, getenv ("HOME"));
1157 strcpy (dflt_passwd.pw_shell, getenv ("SHELL"));
1158
1159 xfree (buf);
1160 if (token)
1161 CloseHandle (token);
1162 }
1163
1164 int
1165 random (void)
1166 {
1167 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
1168 return ((rand () << 15) | rand ());
1169 }
1170
1171 void
1172 srandom (int seed)
1173 {
1174 srand (seed);
1175 }
1176
1177
1178 /* Normalize filename by converting all path separators to
1179 the specified separator. Also conditionally convert upper
1180 case path name components to lower case. */
1181
1182 static void
1183 normalize_filename (register char *fp, char path_sep)
1184 {
1185 char sep;
1186 char *elem;
1187
1188 /* Always lower-case drive letters a-z, even if the filesystem
1189 preserves case in filenames.
1190 This is so filenames can be compared by string comparison
1191 functions that are case-sensitive. Even case-preserving filesystems
1192 do not distinguish case in drive letters. */
1193 if (fp[1] == ':' && *fp >= 'A' && *fp <= 'Z')
1194 {
1195 *fp += 'a' - 'A';
1196 fp += 2;
1197 }
1198
1199 if (NILP (Vw32_downcase_file_names))
1200 {
1201 while (*fp)
1202 {
1203 if (*fp == '/' || *fp == '\\')
1204 *fp = path_sep;
1205 fp++;
1206 }
1207 return;
1208 }
1209
1210 sep = path_sep; /* convert to this path separator */
1211 elem = fp; /* start of current path element */
1212
1213 do {
1214 if (*fp >= 'a' && *fp <= 'z')
1215 elem = 0; /* don't convert this element */
1216
1217 if (*fp == 0 || *fp == ':')
1218 {
1219 sep = *fp; /* restore current separator (or 0) */
1220 *fp = '/'; /* after conversion of this element */
1221 }
1222
1223 if (*fp == '/' || *fp == '\\')
1224 {
1225 if (elem && elem != fp)
1226 {
1227 *fp = 0; /* temporary end of string */
1228 _strlwr (elem); /* while we convert to lower case */
1229 }
1230 *fp = sep; /* convert (or restore) path separator */
1231 elem = fp + 1; /* next element starts after separator */
1232 sep = path_sep;
1233 }
1234 } while (*fp++);
1235 }
1236
1237 /* Destructively turn backslashes into slashes. */
1238 void
1239 dostounix_filename (register char *p)
1240 {
1241 normalize_filename (p, '/');
1242 }
1243
1244 /* Destructively turn slashes into backslashes. */
1245 void
1246 unixtodos_filename (register char *p)
1247 {
1248 normalize_filename (p, '\\');
1249 }
1250
1251 /* Remove all CR's that are followed by a LF.
1252 (From msdos.c...probably should figure out a way to share it,
1253 although this code isn't going to ever change.) */
1254 static int
1255 crlf_to_lf (register int n, register unsigned char *buf)
1256 {
1257 unsigned char *np = buf;
1258 unsigned char *startp = buf;
1259 unsigned char *endp = buf + n;
1260
1261 if (n == 0)
1262 return n;
1263 while (buf < endp - 1)
1264 {
1265 if (*buf == 0x0d)
1266 {
1267 if (*(++buf) != 0x0a)
1268 *np++ = 0x0d;
1269 }
1270 else
1271 *np++ = *buf++;
1272 }
1273 if (buf < endp)
1274 *np++ = *buf++;
1275 return np - startp;
1276 }
1277
1278 /* Parse the root part of file name, if present. Return length and
1279 optionally store pointer to char after root. */
1280 static int
1281 parse_root (char * name, char ** pPath)
1282 {
1283 char * start = name;
1284
1285 if (name == NULL)
1286 return 0;
1287
1288 /* find the root name of the volume if given */
1289 if (isalpha (name[0]) && name[1] == ':')
1290 {
1291 /* skip past drive specifier */
1292 name += 2;
1293 if (IS_DIRECTORY_SEP (name[0]))
1294 name++;
1295 }
1296 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
1297 {
1298 int slashes = 2;
1299 name += 2;
1300 do
1301 {
1302 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
1303 break;
1304 name++;
1305 }
1306 while ( *name );
1307 if (IS_DIRECTORY_SEP (name[0]))
1308 name++;
1309 }
1310
1311 if (pPath)
1312 *pPath = name;
1313
1314 return name - start;
1315 }
1316
1317 /* Get long base name for name; name is assumed to be absolute. */
1318 static int
1319 get_long_basename (char * name, char * buf, int size)
1320 {
1321 WIN32_FIND_DATA find_data;
1322 HANDLE dir_handle;
1323 int len = 0;
1324
1325 /* must be valid filename, no wild cards or other invalid characters */
1326 if (_mbspbrk (name, "*?|<>\""))
1327 return 0;
1328
1329 dir_handle = FindFirstFile (name, &find_data);
1330 if (dir_handle != INVALID_HANDLE_VALUE)
1331 {
1332 if ((len = strlen (find_data.cFileName)) < size)
1333 memcpy (buf, find_data.cFileName, len + 1);
1334 else
1335 len = 0;
1336 FindClose (dir_handle);
1337 }
1338 return len;
1339 }
1340
1341 /* Get long name for file, if possible (assumed to be absolute). */
1342 BOOL
1343 w32_get_long_filename (char * name, char * buf, int size)
1344 {
1345 char * o = buf;
1346 char * p;
1347 char * q;
1348 char full[ MAX_PATH ];
1349 int len;
1350
1351 len = strlen (name);
1352 if (len >= MAX_PATH)
1353 return FALSE;
1354
1355 /* Use local copy for destructive modification. */
1356 memcpy (full, name, len+1);
1357 unixtodos_filename (full);
1358
1359 /* Copy root part verbatim. */
1360 len = parse_root (full, &p);
1361 memcpy (o, full, len);
1362 o += len;
1363 *o = '\0';
1364 size -= len;
1365
1366 while (p != NULL && *p)
1367 {
1368 q = p;
1369 p = strchr (q, '\\');
1370 if (p) *p = '\0';
1371 len = get_long_basename (full, o, size);
1372 if (len > 0)
1373 {
1374 o += len;
1375 size -= len;
1376 if (p != NULL)
1377 {
1378 *p++ = '\\';
1379 if (size < 2)
1380 return FALSE;
1381 *o++ = '\\';
1382 size--;
1383 *o = '\0';
1384 }
1385 }
1386 else
1387 return FALSE;
1388 }
1389
1390 return TRUE;
1391 }
1392
1393 static int
1394 is_unc_volume (const char *filename)
1395 {
1396 const char *ptr = filename;
1397
1398 if (!IS_DIRECTORY_SEP (ptr[0]) || !IS_DIRECTORY_SEP (ptr[1]) || !ptr[2])
1399 return 0;
1400
1401 if (_mbspbrk (ptr + 2, "*?|<>\"\\/"))
1402 return 0;
1403
1404 return 1;
1405 }
1406
1407 /* Routines that are no-ops on NT but are defined to get Emacs to compile. */
1408
1409 int
1410 sigsetmask (int signal_mask)
1411 {
1412 return 0;
1413 }
1414
1415 int
1416 sigmask (int sig)
1417 {
1418 return 0;
1419 }
1420
1421 int
1422 sigblock (int sig)
1423 {
1424 return 0;
1425 }
1426
1427 int
1428 sigunblock (int sig)
1429 {
1430 return 0;
1431 }
1432
1433 int
1434 sigemptyset (sigset_t *set)
1435 {
1436 return 0;
1437 }
1438
1439 int
1440 sigaddset (sigset_t *set, int signo)
1441 {
1442 return 0;
1443 }
1444
1445 int
1446 sigfillset (sigset_t *set)
1447 {
1448 return 0;
1449 }
1450
1451 int
1452 sigprocmask (int how, const sigset_t *set, sigset_t *oset)
1453 {
1454 return 0;
1455 }
1456
1457 int
1458 setpgrp (int pid, int gid)
1459 {
1460 return 0;
1461 }
1462
1463 int
1464 alarm (int seconds)
1465 {
1466 return 0;
1467 }
1468
1469 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
1470
1471 LPBYTE
1472 w32_get_resource (char *key, LPDWORD lpdwtype)
1473 {
1474 LPBYTE lpvalue;
1475 HKEY hrootkey = NULL;
1476 DWORD cbData;
1477
1478 /* Check both the current user and the local machine to see if
1479 we have any resources. */
1480
1481 if (RegOpenKeyEx (HKEY_CURRENT_USER, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
1482 {
1483 lpvalue = NULL;
1484
1485 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
1486 && (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL
1487 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
1488 {
1489 RegCloseKey (hrootkey);
1490 return (lpvalue);
1491 }
1492
1493 xfree (lpvalue);
1494
1495 RegCloseKey (hrootkey);
1496 }
1497
1498 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
1499 {
1500 lpvalue = NULL;
1501
1502 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
1503 && (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL
1504 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
1505 {
1506 RegCloseKey (hrootkey);
1507 return (lpvalue);
1508 }
1509
1510 xfree (lpvalue);
1511
1512 RegCloseKey (hrootkey);
1513 }
1514
1515 return (NULL);
1516 }
1517
1518 char *get_emacs_configuration (void);
1519 extern Lisp_Object Vsystem_configuration;
1520
1521 void
1522 init_environment (char ** argv)
1523 {
1524 static const char * const tempdirs[] = {
1525 "$TMPDIR", "$TEMP", "$TMP", "c:/"
1526 };
1527
1528 int i;
1529
1530 const int imax = sizeof (tempdirs) / sizeof (tempdirs[0]);
1531
1532 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
1533 temporary files and assume "/tmp" if $TMPDIR is unset, which
1534 will break on DOS/Windows. Refuse to work if we cannot find
1535 a directory, not even "c:/", usable for that purpose. */
1536 for (i = 0; i < imax ; i++)
1537 {
1538 const char *tmp = tempdirs[i];
1539
1540 if (*tmp == '$')
1541 tmp = getenv (tmp + 1);
1542 /* Note that `access' can lie to us if the directory resides on a
1543 read-only filesystem, like CD-ROM or a write-protected floppy.
1544 The only way to be really sure is to actually create a file and
1545 see if it succeeds. But I think that's too much to ask. */
1546 if (tmp && _access (tmp, D_OK) == 0)
1547 {
1548 char * var = alloca (strlen (tmp) + 8);
1549 sprintf (var, "TMPDIR=%s", tmp);
1550 _putenv (strdup (var));
1551 break;
1552 }
1553 }
1554 if (i >= imax)
1555 cmd_error_internal
1556 (Fcons (Qerror,
1557 Fcons (build_string ("no usable temporary directories found!!"),
1558 Qnil)),
1559 "While setting TMPDIR: ");
1560
1561 /* Check for environment variables and use registry settings if they
1562 don't exist. Fallback on default values where applicable. */
1563 {
1564 int i;
1565 LPBYTE lpval;
1566 DWORD dwType;
1567 char locale_name[32];
1568 struct stat ignored;
1569 char default_home[MAX_PATH];
1570
1571 static const struct env_entry
1572 {
1573 char * name;
1574 char * def_value;
1575 } dflt_envvars[] =
1576 {
1577 {"HOME", "C:/"},
1578 {"PRELOAD_WINSOCK", NULL},
1579 {"emacs_dir", "C:/emacs"},
1580 {"EMACSLOADPATH", "%emacs_dir%/site-lisp;%emacs_dir%/../site-lisp;%emacs_dir%/lisp;%emacs_dir%/leim"},
1581 {"SHELL", "%emacs_dir%/bin/cmdproxy.exe"},
1582 {"EMACSDATA", "%emacs_dir%/etc"},
1583 {"EMACSPATH", "%emacs_dir%/bin"},
1584 /* We no longer set INFOPATH because Info-default-directory-list
1585 is then ignored. */
1586 /* {"INFOPATH", "%emacs_dir%/info"}, */
1587 {"EMACSDOC", "%emacs_dir%/etc"},
1588 {"TERM", "cmd"},
1589 {"LANG", NULL},
1590 };
1591
1592 #define N_ENV_VARS sizeof (dflt_envvars)/sizeof (dflt_envvars[0])
1593
1594 /* We need to copy dflt_envvars[] and work on the copy because we
1595 don't want the dumped Emacs to inherit the values of
1596 environment variables we saw during dumping (which could be on
1597 a different system). The defaults above must be left intact. */
1598 struct env_entry env_vars[N_ENV_VARS];
1599
1600 for (i = 0; i < N_ENV_VARS; i++)
1601 env_vars[i] = dflt_envvars[i];
1602
1603 /* For backwards compatibility, check if a .emacs file exists in C:/
1604 If not, then we can try to default to the appdata directory under the
1605 user's profile, which is more likely to be writable. */
1606 if (stat ("C:/.emacs", &ignored) < 0)
1607 {
1608 HRESULT profile_result;
1609 /* Dynamically load ShGetFolderPath, as it won't exist on versions
1610 of Windows 95 and NT4 that have not been updated to include
1611 MSIE 5. */
1612 ShGetFolderPath_fn get_folder_path;
1613 get_folder_path = (ShGetFolderPath_fn)
1614 GetProcAddress (GetModuleHandle ("shell32.dll"), "SHGetFolderPathA");
1615
1616 if (get_folder_path != NULL)
1617 {
1618 profile_result = get_folder_path (NULL, CSIDL_APPDATA, NULL,
1619 0, default_home);
1620
1621 /* If we can't get the appdata dir, revert to old behavior. */
1622 if (profile_result == S_OK)
1623 env_vars[0].def_value = default_home;
1624 }
1625 }
1626
1627 /* Get default locale info and use it for LANG. */
1628 if (GetLocaleInfo (LOCALE_USER_DEFAULT,
1629 LOCALE_SABBREVLANGNAME | LOCALE_USE_CP_ACP,
1630 locale_name, sizeof (locale_name)))
1631 {
1632 for (i = 0; i < N_ENV_VARS; i++)
1633 {
1634 if (strcmp (env_vars[i].name, "LANG") == 0)
1635 {
1636 env_vars[i].def_value = locale_name;
1637 break;
1638 }
1639 }
1640 }
1641
1642 #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
1643
1644 /* Treat emacs_dir specially: set it unconditionally based on our
1645 location, if it appears that we are running from the bin subdir
1646 of a standard installation. */
1647 {
1648 char *p;
1649 char modname[MAX_PATH];
1650
1651 if (!GetModuleFileName (NULL, modname, MAX_PATH))
1652 abort ();
1653 if ((p = strrchr (modname, '\\')) == NULL)
1654 abort ();
1655 *p = 0;
1656
1657 if ((p = strrchr (modname, '\\')) && xstrcasecmp (p, "\\bin") == 0)
1658 {
1659 char buf[SET_ENV_BUF_SIZE];
1660
1661 *p = 0;
1662 for (p = modname; *p; p++)
1663 if (*p == '\\') *p = '/';
1664
1665 _snprintf (buf, sizeof (buf)-1, "emacs_dir=%s", modname);
1666 _putenv (strdup (buf));
1667 }
1668 /* Handle running emacs from the build directory: src/oo-spd/i386/ */
1669
1670 /* FIXME: should use substring of get_emacs_configuration ().
1671 But I don't think the Windows build supports alpha, mips etc
1672 anymore, so have taken the easy option for now. */
1673 else if (p && xstrcasecmp (p, "\\i386") == 0)
1674 {
1675 *p = 0;
1676 p = strrchr (modname, '\\');
1677 if (p != NULL)
1678 {
1679 *p = 0;
1680 p = strrchr (modname, '\\');
1681 if (p && xstrcasecmp (p, "\\src") == 0)
1682 {
1683 char buf[SET_ENV_BUF_SIZE];
1684
1685 *p = 0;
1686 for (p = modname; *p; p++)
1687 if (*p == '\\') *p = '/';
1688
1689 _snprintf (buf, sizeof (buf)-1, "emacs_dir=%s", modname);
1690 _putenv (strdup (buf));
1691 }
1692 }
1693 }
1694 }
1695
1696 for (i = 0; i < N_ENV_VARS; i++)
1697 {
1698 if (!getenv (env_vars[i].name))
1699 {
1700 int dont_free = 0;
1701
1702 if ((lpval = w32_get_resource (env_vars[i].name, &dwType)) == NULL
1703 /* Also ignore empty environment variables. */
1704 || *lpval == 0)
1705 {
1706 xfree (lpval);
1707 lpval = env_vars[i].def_value;
1708 dwType = REG_EXPAND_SZ;
1709 dont_free = 1;
1710 }
1711
1712 if (lpval)
1713 {
1714 char buf1[SET_ENV_BUF_SIZE], buf2[SET_ENV_BUF_SIZE];
1715
1716 if (dwType == REG_EXPAND_SZ)
1717 ExpandEnvironmentStrings ((LPSTR) lpval, buf1, sizeof (buf1));
1718 else if (dwType == REG_SZ)
1719 strcpy (buf1, lpval);
1720 if (dwType == REG_EXPAND_SZ || dwType == REG_SZ)
1721 {
1722 _snprintf (buf2, sizeof (buf2)-1, "%s=%s", env_vars[i].name,
1723 buf1);
1724 _putenv (strdup (buf2));
1725 }
1726
1727 if (!dont_free)
1728 xfree (lpval);
1729 }
1730 }
1731 }
1732 }
1733
1734 /* Rebuild system configuration to reflect invoking system. */
1735 Vsystem_configuration = build_string (EMACS_CONFIGURATION);
1736
1737 /* Another special case: on NT, the PATH variable is actually named
1738 "Path" although cmd.exe (perhaps NT itself) arranges for
1739 environment variable lookup and setting to be case insensitive.
1740 However, Emacs assumes a fully case sensitive environment, so we
1741 need to change "Path" to "PATH" to match the expectations of
1742 various elisp packages. We do this by the sneaky method of
1743 modifying the string in the C runtime environ entry.
1744
1745 The same applies to COMSPEC. */
1746 {
1747 char ** envp;
1748
1749 for (envp = environ; *envp; envp++)
1750 if (_strnicmp (*envp, "PATH=", 5) == 0)
1751 memcpy (*envp, "PATH=", 5);
1752 else if (_strnicmp (*envp, "COMSPEC=", 8) == 0)
1753 memcpy (*envp, "COMSPEC=", 8);
1754 }
1755
1756 /* Remember the initial working directory for getwd, then make the
1757 real wd be the location of emacs.exe to avoid conflicts when
1758 renaming or deleting directories. (We also don't call chdir when
1759 running subprocesses for the same reason.) */
1760 if (!GetCurrentDirectory (MAXPATHLEN, startup_dir))
1761 abort ();
1762
1763 {
1764 char *p;
1765 static char modname[MAX_PATH];
1766
1767 if (!GetModuleFileName (NULL, modname, MAX_PATH))
1768 abort ();
1769 if ((p = strrchr (modname, '\\')) == NULL)
1770 abort ();
1771 *p = 0;
1772
1773 SetCurrentDirectory (modname);
1774
1775 /* Ensure argv[0] has the full path to Emacs. */
1776 *p = '\\';
1777 argv[0] = modname;
1778 }
1779
1780 /* Determine if there is a middle mouse button, to allow parse_button
1781 to decide whether right mouse events should be mouse-2 or
1782 mouse-3. */
1783 w32_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);
1784
1785 init_user_info ();
1786 }
1787
1788 char *
1789 emacs_root_dir (void)
1790 {
1791 static char root_dir[FILENAME_MAX];
1792 const char *p;
1793
1794 p = getenv ("emacs_dir");
1795 if (p == NULL)
1796 abort ();
1797 strcpy (root_dir, p);
1798 root_dir[parse_root (root_dir, NULL)] = '\0';
1799 dostounix_filename (root_dir);
1800 return root_dir;
1801 }
1802
1803 /* We don't have scripts to automatically determine the system configuration
1804 for Emacs before it's compiled, and we don't want to have to make the
1805 user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
1806 routine. */
1807
1808 char *
1809 get_emacs_configuration (void)
1810 {
1811 char *arch, *oem, *os;
1812 int build_num;
1813 static char configuration_buffer[32];
1814
1815 /* Determine the processor type. */
1816 switch (get_processor_type ())
1817 {
1818
1819 #ifdef PROCESSOR_INTEL_386
1820 case PROCESSOR_INTEL_386:
1821 case PROCESSOR_INTEL_486:
1822 case PROCESSOR_INTEL_PENTIUM:
1823 arch = "i386";
1824 break;
1825 #endif
1826
1827 #ifdef PROCESSOR_MIPS_R2000
1828 case PROCESSOR_MIPS_R2000:
1829 case PROCESSOR_MIPS_R3000:
1830 case PROCESSOR_MIPS_R4000:
1831 arch = "mips";
1832 break;
1833 #endif
1834
1835 #ifdef PROCESSOR_ALPHA_21064
1836 case PROCESSOR_ALPHA_21064:
1837 arch = "alpha";
1838 break;
1839 #endif
1840
1841 default:
1842 arch = "unknown";
1843 break;
1844 }
1845
1846 /* Use the OEM field to reflect the compiler/library combination. */
1847 #ifdef _MSC_VER
1848 #define COMPILER_NAME "msvc"
1849 #else
1850 #ifdef __GNUC__
1851 #define COMPILER_NAME "mingw"
1852 #else
1853 #define COMPILER_NAME "unknown"
1854 #endif
1855 #endif
1856 oem = COMPILER_NAME;
1857
1858 switch (osinfo_cache.dwPlatformId) {
1859 case VER_PLATFORM_WIN32_NT:
1860 os = "nt";
1861 build_num = osinfo_cache.dwBuildNumber;
1862 break;
1863 case VER_PLATFORM_WIN32_WINDOWS:
1864 if (osinfo_cache.dwMinorVersion == 0) {
1865 os = "windows95";
1866 } else {
1867 os = "windows98";
1868 }
1869 build_num = LOWORD (osinfo_cache.dwBuildNumber);
1870 break;
1871 case VER_PLATFORM_WIN32s:
1872 /* Not supported, should not happen. */
1873 os = "windows32s";
1874 build_num = LOWORD (osinfo_cache.dwBuildNumber);
1875 break;
1876 default:
1877 os = "unknown";
1878 build_num = 0;
1879 break;
1880 }
1881
1882 if (osinfo_cache.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1883 sprintf (configuration_buffer, "%s-%s-%s%d.%d.%d", arch, oem, os,
1884 get_w32_major_version (), get_w32_minor_version (), build_num);
1885 } else {
1886 sprintf (configuration_buffer, "%s-%s-%s.%d", arch, oem, os, build_num);
1887 }
1888
1889 return configuration_buffer;
1890 }
1891
1892 char *
1893 get_emacs_configuration_options (void)
1894 {
1895 static char *options_buffer;
1896 char cv[32]; /* Enough for COMPILER_VERSION. */
1897 char *options[] = {
1898 cv, /* To be filled later. */
1899 #ifdef EMACSDEBUG
1900 " --no-opt",
1901 #endif
1902 /* configure.bat already sets USER_CFLAGS and USER_LDFLAGS
1903 with a starting space to save work here. */
1904 #ifdef USER_CFLAGS
1905 " --cflags", USER_CFLAGS,
1906 #endif
1907 #ifdef USER_LDFLAGS
1908 " --ldflags", USER_LDFLAGS,
1909 #endif
1910 NULL
1911 };
1912 size_t size = 0;
1913 int i;
1914
1915 /* Work out the effective configure options for this build. */
1916 #ifdef _MSC_VER
1917 #define COMPILER_VERSION "--with-msvc (%d.%02d)", _MSC_VER / 100, _MSC_VER % 100
1918 #else
1919 #ifdef __GNUC__
1920 #define COMPILER_VERSION "--with-gcc (%d.%d)", __GNUC__, __GNUC_MINOR__
1921 #else
1922 #define COMPILER_VERSION ""
1923 #endif
1924 #endif
1925
1926 if (_snprintf (cv, sizeof (cv) - 1, COMPILER_VERSION) < 0)
1927 return "Error: not enough space for compiler version";
1928 cv[sizeof (cv) - 1] = '\0';
1929
1930 for (i = 0; options[i]; i++)
1931 size += strlen (options[i]);
1932
1933 options_buffer = xmalloc (size + 1);
1934 options_buffer[0] = '\0';
1935
1936 for (i = 0; options[i]; i++)
1937 strcat (options_buffer, options[i]);
1938
1939 return options_buffer;
1940 }
1941
1942
1943 #include <sys/timeb.h>
1944
1945 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
1946 void
1947 gettimeofday (struct timeval *tv, struct timezone *tz)
1948 {
1949 struct _timeb tb;
1950 _ftime (&tb);
1951
1952 tv->tv_sec = tb.time;
1953 tv->tv_usec = tb.millitm * 1000L;
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 (wnet_enum_handle, &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 char drive_root[4];
3267 UINT devtype;
3268 WIN32_FIND_DATA wfd;
3269 HANDLE fh;
3270 unsigned __int64 fake_inode;
3271 int permission;
3272 int len;
3273 int rootdir = FALSE;
3274 PSECURITY_DESCRIPTOR psd = NULL;
3275
3276 if (path == NULL || buf == NULL)
3277 {
3278 errno = EFAULT;
3279 return -1;
3280 }
3281
3282 name = (char *) map_w32_filename (path, &path);
3283 /* Must be valid filename, no wild cards or other invalid
3284 characters. We use _mbspbrk to support multibyte strings that
3285 might look to strpbrk as if they included literal *, ?, and other
3286 characters mentioned below that are disallowed by Windows
3287 filesystems. */
3288 if (_mbspbrk (name, "*?|<>\""))
3289 {
3290 errno = ENOENT;
3291 return -1;
3292 }
3293
3294 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
3295 r = IS_DEVICE_SEP (name[1]) ? &name[2] : name;
3296 if (IS_DIRECTORY_SEP (r[0]) && r[1] == '.' && r[2] == '.' && r[3] == '\0')
3297 {
3298 r[1] = r[2] = '\0';
3299 }
3300
3301 /* Remove trailing directory separator, unless name is the root
3302 directory of a drive or UNC volume in which case ensure there
3303 is a trailing separator. */
3304 len = strlen (name);
3305 rootdir = (path >= name + len - 1
3306 && (IS_DIRECTORY_SEP (*path) || *path == 0));
3307 name = strcpy (alloca (len + 2), name);
3308
3309 if (is_unc_volume (name))
3310 {
3311 DWORD attrs = unc_volume_file_attributes (name);
3312
3313 if (attrs == -1)
3314 return -1;
3315
3316 memset (&wfd, 0, sizeof (wfd));
3317 wfd.dwFileAttributes = attrs;
3318 wfd.ftCreationTime = utc_base_ft;
3319 wfd.ftLastAccessTime = utc_base_ft;
3320 wfd.ftLastWriteTime = utc_base_ft;
3321 strcpy (wfd.cFileName, name);
3322 }
3323 else if (rootdir)
3324 {
3325 if (!IS_DIRECTORY_SEP (name[len-1]))
3326 strcat (name, "\\");
3327 if (GetDriveType (name) < 2)
3328 {
3329 errno = ENOENT;
3330 return -1;
3331 }
3332 memset (&wfd, 0, sizeof (wfd));
3333 wfd.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
3334 wfd.ftCreationTime = utc_base_ft;
3335 wfd.ftLastAccessTime = utc_base_ft;
3336 wfd.ftLastWriteTime = utc_base_ft;
3337 strcpy (wfd.cFileName, name);
3338 }
3339 else
3340 {
3341 if (IS_DIRECTORY_SEP (name[len-1]))
3342 name[len - 1] = 0;
3343
3344 /* (This is hacky, but helps when doing file completions on
3345 network drives.) Optimize by using information available from
3346 active readdir if possible. */
3347 len = strlen (dir_pathname);
3348 if (IS_DIRECTORY_SEP (dir_pathname[len-1]))
3349 len--;
3350 if (dir_find_handle != INVALID_HANDLE_VALUE
3351 && strnicmp (name, dir_pathname, len) == 0
3352 && IS_DIRECTORY_SEP (name[len])
3353 && xstrcasecmp (name + len + 1, dir_static.d_name) == 0)
3354 {
3355 /* This was the last entry returned by readdir. */
3356 wfd = dir_find_data;
3357 }
3358 else
3359 {
3360 logon_network_drive (name);
3361
3362 fh = FindFirstFile (name, &wfd);
3363 if (fh == INVALID_HANDLE_VALUE)
3364 {
3365 errno = ENOENT;
3366 return -1;
3367 }
3368 FindClose (fh);
3369 }
3370 }
3371
3372 if (!(NILP (Vw32_get_true_file_attributes)
3373 || (EQ (Vw32_get_true_file_attributes, Qlocal) && is_slow_fs (name)))
3374 /* No access rights required to get info. */
3375 && (fh = CreateFile (name, 0, 0, NULL, OPEN_EXISTING,
3376 FILE_FLAG_BACKUP_SEMANTICS, NULL))
3377 != INVALID_HANDLE_VALUE)
3378 {
3379 /* This is more accurate in terms of gettting the correct number
3380 of links, but is quite slow (it is noticeable when Emacs is
3381 making a list of file name completions). */
3382 BY_HANDLE_FILE_INFORMATION info;
3383
3384 if (GetFileInformationByHandle (fh, &info))
3385 {
3386 buf->st_nlink = info.nNumberOfLinks;
3387 /* Might as well use file index to fake inode values, but this
3388 is not guaranteed to be unique unless we keep a handle open
3389 all the time (even then there are situations where it is
3390 not unique). Reputedly, there are at most 48 bits of info
3391 (on NTFS, presumably less on FAT). */
3392 fake_inode = info.nFileIndexHigh;
3393 fake_inode <<= 32;
3394 fake_inode += info.nFileIndexLow;
3395 }
3396 else
3397 {
3398 buf->st_nlink = 1;
3399 fake_inode = 0;
3400 }
3401
3402 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
3403 {
3404 buf->st_mode = S_IFDIR;
3405 }
3406 else
3407 {
3408 switch (GetFileType (fh))
3409 {
3410 case FILE_TYPE_DISK:
3411 buf->st_mode = S_IFREG;
3412 break;
3413 case FILE_TYPE_PIPE:
3414 buf->st_mode = S_IFIFO;
3415 break;
3416 case FILE_TYPE_CHAR:
3417 case FILE_TYPE_UNKNOWN:
3418 default:
3419 buf->st_mode = S_IFCHR;
3420 }
3421 }
3422 CloseHandle (fh);
3423 psd = get_file_security_desc (name);
3424 get_file_owner_and_group (psd, name, buf);
3425 }
3426 else
3427 {
3428 /* Don't bother to make this information more accurate. */
3429 buf->st_mode = (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ?
3430 S_IFDIR : S_IFREG;
3431 buf->st_nlink = 1;
3432 fake_inode = 0;
3433
3434 get_file_owner_and_group (NULL, name, buf);
3435 }
3436 xfree (psd);
3437
3438 #if 0
3439 /* Not sure if there is any point in this. */
3440 if (!NILP (Vw32_generate_fake_inodes))
3441 fake_inode = generate_inode_val (name);
3442 else if (fake_inode == 0)
3443 {
3444 /* For want of something better, try to make everything unique. */
3445 static DWORD gen_num = 0;
3446 fake_inode = ++gen_num;
3447 }
3448 #endif
3449
3450 /* MSVC defines _ino_t to be short; other libc's might not. */
3451 if (sizeof (buf->st_ino) == 2)
3452 buf->st_ino = fake_inode ^ (fake_inode >> 16);
3453 else
3454 buf->st_ino = fake_inode;
3455
3456 /* volume_info is set indirectly by map_w32_filename */
3457 buf->st_dev = volume_info.serialnum;
3458 buf->st_rdev = volume_info.serialnum;
3459
3460 buf->st_size = wfd.nFileSizeHigh;
3461 buf->st_size <<= 32;
3462 buf->st_size += wfd.nFileSizeLow;
3463
3464 /* Convert timestamps to Unix format. */
3465 buf->st_mtime = convert_time (wfd.ftLastWriteTime);
3466 buf->st_atime = convert_time (wfd.ftLastAccessTime);
3467 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
3468 buf->st_ctime = convert_time (wfd.ftCreationTime);
3469 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
3470
3471 /* determine rwx permissions */
3472 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
3473 permission = S_IREAD;
3474 else
3475 permission = S_IREAD | S_IWRITE;
3476
3477 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
3478 permission |= S_IEXEC;
3479 else if (is_exec (name))
3480 permission |= S_IEXEC;
3481
3482 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
3483
3484 return 0;
3485 }
3486
3487 /* Provide fstat and utime as well as stat for consistent handling of
3488 file timestamps. */
3489 int
3490 fstat (int desc, struct stat * buf)
3491 {
3492 HANDLE fh = (HANDLE) _get_osfhandle (desc);
3493 BY_HANDLE_FILE_INFORMATION info;
3494 unsigned __int64 fake_inode;
3495 int permission;
3496
3497 switch (GetFileType (fh) & ~FILE_TYPE_REMOTE)
3498 {
3499 case FILE_TYPE_DISK:
3500 buf->st_mode = S_IFREG;
3501 if (!GetFileInformationByHandle (fh, &info))
3502 {
3503 errno = EACCES;
3504 return -1;
3505 }
3506 break;
3507 case FILE_TYPE_PIPE:
3508 buf->st_mode = S_IFIFO;
3509 goto non_disk;
3510 case FILE_TYPE_CHAR:
3511 case FILE_TYPE_UNKNOWN:
3512 default:
3513 buf->st_mode = S_IFCHR;
3514 non_disk:
3515 memset (&info, 0, sizeof (info));
3516 info.dwFileAttributes = 0;
3517 info.ftCreationTime = utc_base_ft;
3518 info.ftLastAccessTime = utc_base_ft;
3519 info.ftLastWriteTime = utc_base_ft;
3520 }
3521
3522 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
3523 buf->st_mode = S_IFDIR;
3524
3525 buf->st_nlink = info.nNumberOfLinks;
3526 /* Might as well use file index to fake inode values, but this
3527 is not guaranteed to be unique unless we keep a handle open
3528 all the time (even then there are situations where it is
3529 not unique). Reputedly, there are at most 48 bits of info
3530 (on NTFS, presumably less on FAT). */
3531 fake_inode = info.nFileIndexHigh;
3532 fake_inode <<= 32;
3533 fake_inode += info.nFileIndexLow;
3534
3535 /* MSVC defines _ino_t to be short; other libc's might not. */
3536 if (sizeof (buf->st_ino) == 2)
3537 buf->st_ino = fake_inode ^ (fake_inode >> 16);
3538 else
3539 buf->st_ino = fake_inode;
3540
3541 /* Consider files to belong to current user.
3542 FIXME: this should use GetSecurityInfo API, but it is only
3543 available for _WIN32_WINNT >= 0x501. */
3544 buf->st_uid = dflt_passwd.pw_uid;
3545 buf->st_gid = dflt_passwd.pw_gid;
3546 strcpy (buf->st_uname, dflt_passwd.pw_name);
3547 strcpy (buf->st_gname, dflt_group.gr_name);
3548
3549 buf->st_dev = info.dwVolumeSerialNumber;
3550 buf->st_rdev = info.dwVolumeSerialNumber;
3551
3552 buf->st_size = info.nFileSizeHigh;
3553 buf->st_size <<= 32;
3554 buf->st_size += info.nFileSizeLow;
3555
3556 /* Convert timestamps to Unix format. */
3557 buf->st_mtime = convert_time (info.ftLastWriteTime);
3558 buf->st_atime = convert_time (info.ftLastAccessTime);
3559 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
3560 buf->st_ctime = convert_time (info.ftCreationTime);
3561 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
3562
3563 /* determine rwx permissions */
3564 if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
3565 permission = S_IREAD;
3566 else
3567 permission = S_IREAD | S_IWRITE;
3568
3569 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
3570 permission |= S_IEXEC;
3571 else
3572 {
3573 #if 0 /* no way of knowing the filename */
3574 char * p = strrchr (name, '.');
3575 if (p != NULL &&
3576 (xstrcasecmp (p, ".exe") == 0 ||
3577 xstrcasecmp (p, ".com") == 0 ||
3578 xstrcasecmp (p, ".bat") == 0 ||
3579 xstrcasecmp (p, ".cmd") == 0))
3580 permission |= S_IEXEC;
3581 #endif
3582 }
3583
3584 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
3585
3586 return 0;
3587 }
3588
3589 int
3590 utime (const char *name, struct utimbuf *times)
3591 {
3592 struct utimbuf deftime;
3593 HANDLE fh;
3594 FILETIME mtime;
3595 FILETIME atime;
3596
3597 if (times == NULL)
3598 {
3599 deftime.modtime = deftime.actime = time (NULL);
3600 times = &deftime;
3601 }
3602
3603 /* Need write access to set times. */
3604 fh = CreateFile (name, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
3605 0, OPEN_EXISTING, 0, NULL);
3606 if (fh)
3607 {
3608 convert_from_time_t (times->actime, &atime);
3609 convert_from_time_t (times->modtime, &mtime);
3610 if (!SetFileTime (fh, NULL, &atime, &mtime))
3611 {
3612 CloseHandle (fh);
3613 errno = EACCES;
3614 return -1;
3615 }
3616 CloseHandle (fh);
3617 }
3618 else
3619 {
3620 errno = EINVAL;
3621 return -1;
3622 }
3623 return 0;
3624 }
3625
3626 \f
3627 /* Support for browsing other processes and their attributes. See
3628 process.c for the Lisp bindings. */
3629
3630 /* Helper wrapper functions. */
3631
3632 static HANDLE WINAPI
3633 create_toolhelp32_snapshot (DWORD Flags, DWORD Ignored)
3634 {
3635 static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot = NULL;
3636
3637 if (g_b_init_create_toolhelp32_snapshot == 0)
3638 {
3639 g_b_init_create_toolhelp32_snapshot = 1;
3640 s_pfn_Create_Toolhelp32_Snapshot = (CreateToolhelp32Snapshot_Proc)
3641 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3642 "CreateToolhelp32Snapshot");
3643 }
3644 if (s_pfn_Create_Toolhelp32_Snapshot == NULL)
3645 {
3646 return INVALID_HANDLE_VALUE;
3647 }
3648 return (s_pfn_Create_Toolhelp32_Snapshot (Flags, Ignored));
3649 }
3650
3651 static BOOL WINAPI
3652 process32_first (HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
3653 {
3654 static Process32First_Proc s_pfn_Process32_First = NULL;
3655
3656 if (g_b_init_process32_first == 0)
3657 {
3658 g_b_init_process32_first = 1;
3659 s_pfn_Process32_First = (Process32First_Proc)
3660 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3661 "Process32First");
3662 }
3663 if (s_pfn_Process32_First == NULL)
3664 {
3665 return FALSE;
3666 }
3667 return (s_pfn_Process32_First (hSnapshot, lppe));
3668 }
3669
3670 static BOOL WINAPI
3671 process32_next (HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
3672 {
3673 static Process32Next_Proc s_pfn_Process32_Next = NULL;
3674
3675 if (g_b_init_process32_next == 0)
3676 {
3677 g_b_init_process32_next = 1;
3678 s_pfn_Process32_Next = (Process32Next_Proc)
3679 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3680 "Process32Next");
3681 }
3682 if (s_pfn_Process32_Next == NULL)
3683 {
3684 return FALSE;
3685 }
3686 return (s_pfn_Process32_Next (hSnapshot, lppe));
3687 }
3688
3689 static BOOL WINAPI
3690 open_thread_token (HANDLE ThreadHandle,
3691 DWORD DesiredAccess,
3692 BOOL OpenAsSelf,
3693 PHANDLE TokenHandle)
3694 {
3695 static OpenThreadToken_Proc s_pfn_Open_Thread_Token = NULL;
3696 HMODULE hm_advapi32 = NULL;
3697 if (is_windows_9x () == TRUE)
3698 {
3699 SetLastError (ERROR_NOT_SUPPORTED);
3700 return FALSE;
3701 }
3702 if (g_b_init_open_thread_token == 0)
3703 {
3704 g_b_init_open_thread_token = 1;
3705 hm_advapi32 = LoadLibrary ("Advapi32.dll");
3706 s_pfn_Open_Thread_Token =
3707 (OpenThreadToken_Proc) GetProcAddress (hm_advapi32, "OpenThreadToken");
3708 }
3709 if (s_pfn_Open_Thread_Token == NULL)
3710 {
3711 SetLastError (ERROR_NOT_SUPPORTED);
3712 return FALSE;
3713 }
3714 return (
3715 s_pfn_Open_Thread_Token (
3716 ThreadHandle,
3717 DesiredAccess,
3718 OpenAsSelf,
3719 TokenHandle)
3720 );
3721 }
3722
3723 static BOOL WINAPI
3724 impersonate_self (SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
3725 {
3726 static ImpersonateSelf_Proc s_pfn_Impersonate_Self = NULL;
3727 HMODULE hm_advapi32 = NULL;
3728 if (is_windows_9x () == TRUE)
3729 {
3730 return FALSE;
3731 }
3732 if (g_b_init_impersonate_self == 0)
3733 {
3734 g_b_init_impersonate_self = 1;
3735 hm_advapi32 = LoadLibrary ("Advapi32.dll");
3736 s_pfn_Impersonate_Self =
3737 (ImpersonateSelf_Proc) GetProcAddress (hm_advapi32, "ImpersonateSelf");
3738 }
3739 if (s_pfn_Impersonate_Self == NULL)
3740 {
3741 return FALSE;
3742 }
3743 return s_pfn_Impersonate_Self (ImpersonationLevel);
3744 }
3745
3746 static BOOL WINAPI
3747 revert_to_self (void)
3748 {
3749 static RevertToSelf_Proc s_pfn_Revert_To_Self = NULL;
3750 HMODULE hm_advapi32 = NULL;
3751 if (is_windows_9x () == TRUE)
3752 {
3753 return FALSE;
3754 }
3755 if (g_b_init_revert_to_self == 0)
3756 {
3757 g_b_init_revert_to_self = 1;
3758 hm_advapi32 = LoadLibrary ("Advapi32.dll");
3759 s_pfn_Revert_To_Self =
3760 (RevertToSelf_Proc) GetProcAddress (hm_advapi32, "RevertToSelf");
3761 }
3762 if (s_pfn_Revert_To_Self == NULL)
3763 {
3764 return FALSE;
3765 }
3766 return s_pfn_Revert_To_Self ();
3767 }
3768
3769 static BOOL WINAPI
3770 get_process_memory_info (HANDLE h_proc,
3771 PPROCESS_MEMORY_COUNTERS mem_counters,
3772 DWORD bufsize)
3773 {
3774 static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info = NULL;
3775 HMODULE hm_psapi = NULL;
3776 if (is_windows_9x () == TRUE)
3777 {
3778 return FALSE;
3779 }
3780 if (g_b_init_get_process_memory_info == 0)
3781 {
3782 g_b_init_get_process_memory_info = 1;
3783 hm_psapi = LoadLibrary ("Psapi.dll");
3784 if (hm_psapi)
3785 s_pfn_Get_Process_Memory_Info = (GetProcessMemoryInfo_Proc)
3786 GetProcAddress (hm_psapi, "GetProcessMemoryInfo");
3787 }
3788 if (s_pfn_Get_Process_Memory_Info == NULL)
3789 {
3790 return FALSE;
3791 }
3792 return s_pfn_Get_Process_Memory_Info (h_proc, mem_counters, bufsize);
3793 }
3794
3795 static BOOL WINAPI
3796 get_process_working_set_size (HANDLE h_proc,
3797 DWORD *minrss,
3798 DWORD *maxrss)
3799 {
3800 static GetProcessWorkingSetSize_Proc
3801 s_pfn_Get_Process_Working_Set_Size = NULL;
3802
3803 if (is_windows_9x () == TRUE)
3804 {
3805 return FALSE;
3806 }
3807 if (g_b_init_get_process_working_set_size == 0)
3808 {
3809 g_b_init_get_process_working_set_size = 1;
3810 s_pfn_Get_Process_Working_Set_Size = (GetProcessWorkingSetSize_Proc)
3811 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3812 "GetProcessWorkingSetSize");
3813 }
3814 if (s_pfn_Get_Process_Working_Set_Size == NULL)
3815 {
3816 return FALSE;
3817 }
3818 return s_pfn_Get_Process_Working_Set_Size (h_proc, minrss, maxrss);
3819 }
3820
3821 static BOOL WINAPI
3822 global_memory_status (MEMORYSTATUS *buf)
3823 {
3824 static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status = NULL;
3825
3826 if (is_windows_9x () == TRUE)
3827 {
3828 return FALSE;
3829 }
3830 if (g_b_init_global_memory_status == 0)
3831 {
3832 g_b_init_global_memory_status = 1;
3833 s_pfn_Global_Memory_Status = (GlobalMemoryStatus_Proc)
3834 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3835 "GlobalMemoryStatus");
3836 }
3837 if (s_pfn_Global_Memory_Status == NULL)
3838 {
3839 return FALSE;
3840 }
3841 return s_pfn_Global_Memory_Status (buf);
3842 }
3843
3844 static BOOL WINAPI
3845 global_memory_status_ex (MEMORY_STATUS_EX *buf)
3846 {
3847 static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex = NULL;
3848
3849 if (is_windows_9x () == TRUE)
3850 {
3851 return FALSE;
3852 }
3853 if (g_b_init_global_memory_status_ex == 0)
3854 {
3855 g_b_init_global_memory_status_ex = 1;
3856 s_pfn_Global_Memory_Status_Ex = (GlobalMemoryStatusEx_Proc)
3857 GetProcAddress (GetModuleHandle ("kernel32.dll"),
3858 "GlobalMemoryStatusEx");
3859 }
3860 if (s_pfn_Global_Memory_Status_Ex == NULL)
3861 {
3862 return FALSE;
3863 }
3864 return s_pfn_Global_Memory_Status_Ex (buf);
3865 }
3866
3867 Lisp_Object
3868 list_system_processes (void)
3869 {
3870 struct gcpro gcpro1;
3871 Lisp_Object proclist = Qnil;
3872 HANDLE h_snapshot;
3873
3874 h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
3875
3876 if (h_snapshot != INVALID_HANDLE_VALUE)
3877 {
3878 PROCESSENTRY32 proc_entry;
3879 DWORD proc_id;
3880 BOOL res;
3881
3882 GCPRO1 (proclist);
3883
3884 proc_entry.dwSize = sizeof (PROCESSENTRY32);
3885 for (res = process32_first (h_snapshot, &proc_entry); res;
3886 res = process32_next (h_snapshot, &proc_entry))
3887 {
3888 proc_id = proc_entry.th32ProcessID;
3889 proclist = Fcons (make_fixnum_or_float (proc_id), proclist);
3890 }
3891
3892 CloseHandle (h_snapshot);
3893 UNGCPRO;
3894 proclist = Fnreverse (proclist);
3895 }
3896
3897 return proclist;
3898 }
3899
3900 static int
3901 enable_privilege (LPCTSTR priv_name, BOOL enable_p, TOKEN_PRIVILEGES *old_priv)
3902 {
3903 TOKEN_PRIVILEGES priv;
3904 DWORD priv_size = sizeof (priv);
3905 DWORD opriv_size = sizeof (*old_priv);
3906 HANDLE h_token = NULL;
3907 HANDLE h_thread = GetCurrentThread ();
3908 int ret_val = 0;
3909 BOOL res;
3910
3911 res = open_thread_token (h_thread,
3912 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
3913 FALSE, &h_token);
3914 if (!res && GetLastError () == ERROR_NO_TOKEN)
3915 {
3916 if (impersonate_self (SecurityImpersonation))
3917 res = open_thread_token (h_thread,
3918 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
3919 FALSE, &h_token);
3920 }
3921 if (res)
3922 {
3923 priv.PrivilegeCount = 1;
3924 priv.Privileges[0].Attributes = enable_p ? SE_PRIVILEGE_ENABLED : 0;
3925 LookupPrivilegeValue (NULL, priv_name, &priv.Privileges[0].Luid);
3926 if (AdjustTokenPrivileges (h_token, FALSE, &priv, priv_size,
3927 old_priv, &opriv_size)
3928 && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
3929 ret_val = 1;
3930 }
3931 if (h_token)
3932 CloseHandle (h_token);
3933
3934 return ret_val;
3935 }
3936
3937 static int
3938 restore_privilege (TOKEN_PRIVILEGES *priv)
3939 {
3940 DWORD priv_size = sizeof (*priv);
3941 HANDLE h_token = NULL;
3942 int ret_val = 0;
3943
3944 if (open_thread_token (GetCurrentThread (),
3945 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
3946 FALSE, &h_token))
3947 {
3948 if (AdjustTokenPrivileges (h_token, FALSE, priv, priv_size, NULL, NULL)
3949 && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
3950 ret_val = 1;
3951 }
3952 if (h_token)
3953 CloseHandle (h_token);
3954
3955 return ret_val;
3956 }
3957
3958 static Lisp_Object
3959 ltime (long time_sec, long time_usec)
3960 {
3961 return list3 (make_number ((time_sec >> 16) & 0xffff),
3962 make_number (time_sec & 0xffff),
3963 make_number (time_usec));
3964 }
3965
3966 #define U64_TO_LISP_TIME(time) ltime ((time) / 1000000L, (time) % 1000000L)
3967
3968 static int
3969 process_times (HANDLE h_proc, Lisp_Object *ctime, Lisp_Object *etime,
3970 Lisp_Object *stime, Lisp_Object *utime, Lisp_Object *ttime,
3971 double *pcpu)
3972 {
3973 FILETIME ft_creation, ft_exit, ft_kernel, ft_user, ft_current;
3974 ULONGLONG tem1, tem2, tem3, tem;
3975
3976 if (!h_proc
3977 || !get_process_times_fn
3978 || !(*get_process_times_fn) (h_proc, &ft_creation, &ft_exit,
3979 &ft_kernel, &ft_user))
3980 return 0;
3981
3982 GetSystemTimeAsFileTime (&ft_current);
3983
3984 FILETIME_TO_U64 (tem1, ft_kernel);
3985 tem1 /= 10L;
3986 *stime = U64_TO_LISP_TIME (tem1);
3987
3988 FILETIME_TO_U64 (tem2, ft_user);
3989 tem2 /= 10L;
3990 *utime = U64_TO_LISP_TIME (tem2);
3991
3992 tem3 = tem1 + tem2;
3993 *ttime = U64_TO_LISP_TIME (tem3);
3994
3995 FILETIME_TO_U64 (tem, ft_creation);
3996 /* Process no 4 (System) returns zero creation time. */
3997 if (tem)
3998 tem = (tem - utc_base) / 10L;
3999 *ctime = U64_TO_LISP_TIME (tem);
4000
4001 if (tem)
4002 {
4003 FILETIME_TO_U64 (tem3, ft_current);
4004 tem = (tem3 - utc_base) / 10L - tem;
4005 }
4006 *etime = U64_TO_LISP_TIME (tem);
4007
4008 if (tem)
4009 {
4010 *pcpu = 100.0 * (tem1 + tem2) / tem;
4011 if (*pcpu > 100)
4012 *pcpu = 100.0;
4013 }
4014 else
4015 *pcpu = 0;
4016
4017 return 1;
4018 }
4019
4020 Lisp_Object
4021 system_process_attributes (Lisp_Object pid)
4022 {
4023 struct gcpro gcpro1, gcpro2, gcpro3;
4024 Lisp_Object attrs = Qnil;
4025 Lisp_Object cmd_str, decoded_cmd, tem;
4026 HANDLE h_snapshot, h_proc;
4027 DWORD proc_id;
4028 int found_proc = 0;
4029 char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
4030 DWORD ulength = sizeof (uname), dlength = sizeof (domain), needed;
4031 DWORD glength = sizeof (gname);
4032 HANDLE token = NULL;
4033 SID_NAME_USE user_type;
4034 unsigned char *buf = NULL;
4035 DWORD blen = 0;
4036 TOKEN_USER user_token;
4037 TOKEN_PRIMARY_GROUP group_token;
4038 unsigned euid;
4039 unsigned egid;
4040 DWORD sess;
4041 PROCESS_MEMORY_COUNTERS mem;
4042 PROCESS_MEMORY_COUNTERS_EX mem_ex;
4043 DWORD minrss, maxrss;
4044 MEMORYSTATUS memst;
4045 MEMORY_STATUS_EX memstex;
4046 double totphys = 0.0;
4047 Lisp_Object ctime, stime, utime, etime, ttime;
4048 double pcpu;
4049 BOOL result = FALSE;
4050
4051 CHECK_NUMBER_OR_FLOAT (pid);
4052 proc_id = FLOATP (pid) ? XFLOAT_DATA (pid) : XINT (pid);
4053
4054 h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
4055
4056 GCPRO3 (attrs, decoded_cmd, tem);
4057
4058 if (h_snapshot != INVALID_HANDLE_VALUE)
4059 {
4060 PROCESSENTRY32 pe;
4061 BOOL res;
4062
4063 pe.dwSize = sizeof (PROCESSENTRY32);
4064 for (res = process32_first (h_snapshot, &pe); res;
4065 res = process32_next (h_snapshot, &pe))
4066 {
4067 if (proc_id == pe.th32ProcessID)
4068 {
4069 if (proc_id == 0)
4070 decoded_cmd = build_string ("Idle");
4071 else
4072 {
4073 /* Decode the command name from locale-specific
4074 encoding. */
4075 cmd_str = make_unibyte_string (pe.szExeFile,
4076 strlen (pe.szExeFile));
4077 decoded_cmd =
4078 code_convert_string_norecord (cmd_str,
4079 Vlocale_coding_system, 0);
4080 }
4081 attrs = Fcons (Fcons (Qcomm, decoded_cmd), attrs);
4082 attrs = Fcons (Fcons (Qppid,
4083 make_fixnum_or_float (pe.th32ParentProcessID)),
4084 attrs);
4085 attrs = Fcons (Fcons (Qpri, make_number (pe.pcPriClassBase)),
4086 attrs);
4087 attrs = Fcons (Fcons (Qthcount,
4088 make_fixnum_or_float (pe.cntThreads)),
4089 attrs);
4090 found_proc = 1;
4091 break;
4092 }
4093 }
4094
4095 CloseHandle (h_snapshot);
4096 }
4097
4098 if (!found_proc)
4099 {
4100 UNGCPRO;
4101 return Qnil;
4102 }
4103
4104 h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
4105 FALSE, proc_id);
4106 /* If we were denied a handle to the process, try again after
4107 enabling the SeDebugPrivilege in our process. */
4108 if (!h_proc)
4109 {
4110 TOKEN_PRIVILEGES priv_current;
4111
4112 if (enable_privilege (SE_DEBUG_NAME, TRUE, &priv_current))
4113 {
4114 h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
4115 FALSE, proc_id);
4116 restore_privilege (&priv_current);
4117 revert_to_self ();
4118 }
4119 }
4120 if (h_proc)
4121 {
4122 result = open_process_token (h_proc, TOKEN_QUERY, &token);
4123 if (result)
4124 {
4125 result = get_token_information (token, TokenUser, NULL, 0, &blen);
4126 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
4127 {
4128 buf = xmalloc (blen);
4129 result = get_token_information (token, TokenUser,
4130 (LPVOID)buf, blen, &needed);
4131 if (result)
4132 {
4133 memcpy (&user_token, buf, sizeof (user_token));
4134 if (!w32_cached_id (user_token.User.Sid, &euid, uname))
4135 {
4136 euid = get_rid (user_token.User.Sid);
4137 result = lookup_account_sid (NULL, user_token.User.Sid,
4138 uname, &ulength,
4139 domain, &dlength,
4140 &user_type);
4141 if (result)
4142 w32_add_to_cache (user_token.User.Sid, euid, uname);
4143 else
4144 {
4145 strcpy (uname, "unknown");
4146 result = TRUE;
4147 }
4148 }
4149 ulength = strlen (uname);
4150 }
4151 }
4152 }
4153 if (result)
4154 {
4155 /* Determine a reasonable euid and gid values. */
4156 if (xstrcasecmp ("administrator", uname) == 0)
4157 {
4158 euid = 500; /* well-known Administrator uid */
4159 egid = 513; /* well-known None gid */
4160 }
4161 else
4162 {
4163 /* Get group id and name. */
4164 result = get_token_information (token, TokenPrimaryGroup,
4165 (LPVOID)buf, blen, &needed);
4166 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
4167 {
4168 buf = xrealloc (buf, blen = needed);
4169 result = get_token_information (token, TokenPrimaryGroup,
4170 (LPVOID)buf, blen, &needed);
4171 }
4172 if (result)
4173 {
4174 memcpy (&group_token, buf, sizeof (group_token));
4175 if (!w32_cached_id (group_token.PrimaryGroup, &egid, gname))
4176 {
4177 egid = get_rid (group_token.PrimaryGroup);
4178 dlength = sizeof (domain);
4179 result =
4180 lookup_account_sid (NULL, group_token.PrimaryGroup,
4181 gname, &glength, NULL, &dlength,
4182 &user_type);
4183 if (result)
4184 w32_add_to_cache (group_token.PrimaryGroup,
4185 egid, gname);
4186 else
4187 {
4188 strcpy (gname, "None");
4189 result = TRUE;
4190 }
4191 }
4192 glength = strlen (gname);
4193 }
4194 }
4195 }
4196 xfree (buf);
4197 }
4198 if (!result)
4199 {
4200 if (!is_windows_9x ())
4201 {
4202 /* We couldn't open the process token, presumably because of
4203 insufficient access rights. Assume this process is run
4204 by the system. */
4205 strcpy (uname, "SYSTEM");
4206 strcpy (gname, "None");
4207 euid = 18; /* SYSTEM */
4208 egid = 513; /* None */
4209 glength = strlen (gname);
4210 ulength = strlen (uname);
4211 }
4212 /* If we are running under Windows 9X, where security calls are
4213 not supported, we assume all processes are run by the current
4214 user. */
4215 else if (GetUserName (uname, &ulength))
4216 {
4217 if (xstrcasecmp ("administrator", uname) == 0)
4218 euid = 0;
4219 else
4220 euid = 123;
4221 egid = euid;
4222 strcpy (gname, "None");
4223 glength = strlen (gname);
4224 ulength = strlen (uname);
4225 }
4226 else
4227 {
4228 euid = 123;
4229 egid = 123;
4230 strcpy (uname, "administrator");
4231 ulength = strlen (uname);
4232 strcpy (gname, "None");
4233 glength = strlen (gname);
4234 }
4235 if (token)
4236 CloseHandle (token);
4237 }
4238
4239 attrs = Fcons (Fcons (Qeuid, make_fixnum_or_float (euid)), attrs);
4240 tem = make_unibyte_string (uname, ulength);
4241 attrs = Fcons (Fcons (Quser,
4242 code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
4243 attrs);
4244 attrs = Fcons (Fcons (Qegid, make_fixnum_or_float (egid)), attrs);
4245 tem = make_unibyte_string (gname, glength);
4246 attrs = Fcons (Fcons (Qgroup,
4247 code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
4248 attrs);
4249
4250 if (global_memory_status_ex (&memstex))
4251 #if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
4252 totphys = memstex.ullTotalPhys / 1024.0;
4253 #else
4254 /* Visual Studio 6 cannot convert an unsigned __int64 type to
4255 double, so we need to do this for it... */
4256 {
4257 DWORD tot_hi = memstex.ullTotalPhys >> 32;
4258 DWORD tot_md = (memstex.ullTotalPhys & 0x00000000ffffffff) >> 10;
4259 DWORD tot_lo = memstex.ullTotalPhys % 1024;
4260
4261 totphys = tot_hi * 4194304.0 + tot_md + tot_lo / 1024.0;
4262 }
4263 #endif /* __GNUC__ || _MSC_VER >= 1300 */
4264 else if (global_memory_status (&memst))
4265 totphys = memst.dwTotalPhys / 1024.0;
4266
4267 if (h_proc
4268 && get_process_memory_info (h_proc, (PROCESS_MEMORY_COUNTERS *)&mem_ex,
4269 sizeof (mem_ex)))
4270 {
4271 DWORD rss = mem_ex.WorkingSetSize / 1024;
4272
4273 attrs = Fcons (Fcons (Qmajflt,
4274 make_fixnum_or_float (mem_ex.PageFaultCount)),
4275 attrs);
4276 attrs = Fcons (Fcons (Qvsize,
4277 make_fixnum_or_float (mem_ex.PrivateUsage / 1024)),
4278 attrs);
4279 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (rss)), attrs);
4280 if (totphys)
4281 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
4282 }
4283 else if (h_proc
4284 && get_process_memory_info (h_proc, &mem, sizeof (mem)))
4285 {
4286 DWORD rss = mem_ex.WorkingSetSize / 1024;
4287
4288 attrs = Fcons (Fcons (Qmajflt,
4289 make_fixnum_or_float (mem.PageFaultCount)),
4290 attrs);
4291 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (rss)), attrs);
4292 if (totphys)
4293 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
4294 }
4295 else if (h_proc
4296 && get_process_working_set_size (h_proc, &minrss, &maxrss))
4297 {
4298 DWORD rss = maxrss / 1024;
4299
4300 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (maxrss / 1024)), attrs);
4301 if (totphys)
4302 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
4303 }
4304
4305 if (process_times (h_proc, &ctime, &etime, &stime, &utime, &ttime, &pcpu))
4306 {
4307 attrs = Fcons (Fcons (Qutime, utime), attrs);
4308 attrs = Fcons (Fcons (Qstime, stime), attrs);
4309 attrs = Fcons (Fcons (Qtime, ttime), attrs);
4310 attrs = Fcons (Fcons (Qstart, ctime), attrs);
4311 attrs = Fcons (Fcons (Qetime, etime), attrs);
4312 attrs = Fcons (Fcons (Qpcpu, make_float (pcpu)), attrs);
4313 }
4314
4315 /* FIXME: Retrieve command line by walking the PEB of the process. */
4316
4317 if (h_proc)
4318 CloseHandle (h_proc);
4319 UNGCPRO;
4320 return attrs;
4321 }
4322
4323 \f
4324 /* Wrappers for winsock functions to map between our file descriptors
4325 and winsock's handles; also set h_errno for convenience.
4326
4327 To allow Emacs to run on systems which don't have winsock support
4328 installed, we dynamically link to winsock on startup if present, and
4329 otherwise provide the minimum necessary functionality
4330 (eg. gethostname). */
4331
4332 /* function pointers for relevant socket functions */
4333 int (PASCAL *pfn_WSAStartup) (WORD wVersionRequired, LPWSADATA lpWSAData);
4334 void (PASCAL *pfn_WSASetLastError) (int iError);
4335 int (PASCAL *pfn_WSAGetLastError) (void);
4336 int (PASCAL *pfn_WSAEventSelect) (SOCKET s, HANDLE hEventObject, long lNetworkEvents);
4337 HANDLE (PASCAL *pfn_WSACreateEvent) (void);
4338 int (PASCAL *pfn_WSACloseEvent) (HANDLE hEvent);
4339 int (PASCAL *pfn_socket) (int af, int type, int protocol);
4340 int (PASCAL *pfn_bind) (SOCKET s, const struct sockaddr *addr, int namelen);
4341 int (PASCAL *pfn_connect) (SOCKET s, const struct sockaddr *addr, int namelen);
4342 int (PASCAL *pfn_ioctlsocket) (SOCKET s, long cmd, u_long *argp);
4343 int (PASCAL *pfn_recv) (SOCKET s, char * buf, int len, int flags);
4344 int (PASCAL *pfn_send) (SOCKET s, const char * buf, int len, int flags);
4345 int (PASCAL *pfn_closesocket) (SOCKET s);
4346 int (PASCAL *pfn_shutdown) (SOCKET s, int how);
4347 int (PASCAL *pfn_WSACleanup) (void);
4348
4349 u_short (PASCAL *pfn_htons) (u_short hostshort);
4350 u_short (PASCAL *pfn_ntohs) (u_short netshort);
4351 unsigned long (PASCAL *pfn_inet_addr) (const char * cp);
4352 int (PASCAL *pfn_gethostname) (char * name, int namelen);
4353 struct hostent * (PASCAL *pfn_gethostbyname) (const char * name);
4354 struct servent * (PASCAL *pfn_getservbyname) (const char * name, const char * proto);
4355 int (PASCAL *pfn_getpeername) (SOCKET s, struct sockaddr *addr, int * namelen);
4356 int (PASCAL *pfn_setsockopt) (SOCKET s, int level, int optname,
4357 const char * optval, int optlen);
4358 int (PASCAL *pfn_listen) (SOCKET s, int backlog);
4359 int (PASCAL *pfn_getsockname) (SOCKET s, struct sockaddr * name,
4360 int * namelen);
4361 SOCKET (PASCAL *pfn_accept) (SOCKET s, struct sockaddr * addr, int * addrlen);
4362 int (PASCAL *pfn_recvfrom) (SOCKET s, char * buf, int len, int flags,
4363 struct sockaddr * from, int * fromlen);
4364 int (PASCAL *pfn_sendto) (SOCKET s, const char * buf, int len, int flags,
4365 const struct sockaddr * to, int tolen);
4366
4367 /* SetHandleInformation is only needed to make sockets non-inheritable. */
4368 BOOL (WINAPI *pfn_SetHandleInformation) (HANDLE object, DWORD mask, DWORD flags);
4369 #ifndef HANDLE_FLAG_INHERIT
4370 #define HANDLE_FLAG_INHERIT 1
4371 #endif
4372
4373 HANDLE winsock_lib;
4374 static int winsock_inuse;
4375
4376 BOOL
4377 term_winsock (void)
4378 {
4379 if (winsock_lib != NULL && winsock_inuse == 0)
4380 {
4381 /* Not sure what would cause WSAENETDOWN, or even if it can happen
4382 after WSAStartup returns successfully, but it seems reasonable
4383 to allow unloading winsock anyway in that case. */
4384 if (pfn_WSACleanup () == 0 ||
4385 pfn_WSAGetLastError () == WSAENETDOWN)
4386 {
4387 if (FreeLibrary (winsock_lib))
4388 winsock_lib = NULL;
4389 return TRUE;
4390 }
4391 }
4392 return FALSE;
4393 }
4394
4395 BOOL
4396 init_winsock (int load_now)
4397 {
4398 WSADATA winsockData;
4399
4400 if (winsock_lib != NULL)
4401 return TRUE;
4402
4403 pfn_SetHandleInformation
4404 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
4405 "SetHandleInformation");
4406
4407 winsock_lib = LoadLibrary ("Ws2_32.dll");
4408
4409 if (winsock_lib != NULL)
4410 {
4411 /* dynamically link to socket functions */
4412
4413 #define LOAD_PROC(fn) \
4414 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
4415 goto fail;
4416
4417 LOAD_PROC (WSAStartup);
4418 LOAD_PROC (WSASetLastError);
4419 LOAD_PROC (WSAGetLastError);
4420 LOAD_PROC (WSAEventSelect);
4421 LOAD_PROC (WSACreateEvent);
4422 LOAD_PROC (WSACloseEvent);
4423 LOAD_PROC (socket);
4424 LOAD_PROC (bind);
4425 LOAD_PROC (connect);
4426 LOAD_PROC (ioctlsocket);
4427 LOAD_PROC (recv);
4428 LOAD_PROC (send);
4429 LOAD_PROC (closesocket);
4430 LOAD_PROC (shutdown);
4431 LOAD_PROC (htons);
4432 LOAD_PROC (ntohs);
4433 LOAD_PROC (inet_addr);
4434 LOAD_PROC (gethostname);
4435 LOAD_PROC (gethostbyname);
4436 LOAD_PROC (getservbyname);
4437 LOAD_PROC (getpeername);
4438 LOAD_PROC (WSACleanup);
4439 LOAD_PROC (setsockopt);
4440 LOAD_PROC (listen);
4441 LOAD_PROC (getsockname);
4442 LOAD_PROC (accept);
4443 LOAD_PROC (recvfrom);
4444 LOAD_PROC (sendto);
4445 #undef LOAD_PROC
4446
4447 /* specify version 1.1 of winsock */
4448 if (pfn_WSAStartup (0x101, &winsockData) == 0)
4449 {
4450 if (winsockData.wVersion != 0x101)
4451 goto fail;
4452
4453 if (!load_now)
4454 {
4455 /* Report that winsock exists and is usable, but leave
4456 socket functions disabled. I am assuming that calling
4457 WSAStartup does not require any network interaction,
4458 and in particular does not cause or require a dial-up
4459 connection to be established. */
4460
4461 pfn_WSACleanup ();
4462 FreeLibrary (winsock_lib);
4463 winsock_lib = NULL;
4464 }
4465 winsock_inuse = 0;
4466 return TRUE;
4467 }
4468
4469 fail:
4470 FreeLibrary (winsock_lib);
4471 winsock_lib = NULL;
4472 }
4473
4474 return FALSE;
4475 }
4476
4477
4478 int h_errno = 0;
4479
4480 /* function to set h_errno for compatibility; map winsock error codes to
4481 normal system codes where they overlap (non-overlapping definitions
4482 are already in <sys/socket.h> */
4483 static void
4484 set_errno (void)
4485 {
4486 if (winsock_lib == NULL)
4487 h_errno = EINVAL;
4488 else
4489 h_errno = pfn_WSAGetLastError ();
4490
4491 switch (h_errno)
4492 {
4493 case WSAEACCES: h_errno = EACCES; break;
4494 case WSAEBADF: h_errno = EBADF; break;
4495 case WSAEFAULT: h_errno = EFAULT; break;
4496 case WSAEINTR: h_errno = EINTR; break;
4497 case WSAEINVAL: h_errno = EINVAL; break;
4498 case WSAEMFILE: h_errno = EMFILE; break;
4499 case WSAENAMETOOLONG: h_errno = ENAMETOOLONG; break;
4500 case WSAENOTEMPTY: h_errno = ENOTEMPTY; break;
4501 }
4502 errno = h_errno;
4503 }
4504
4505 static void
4506 check_errno (void)
4507 {
4508 if (h_errno == 0 && winsock_lib != NULL)
4509 pfn_WSASetLastError (0);
4510 }
4511
4512 /* Extend strerror to handle the winsock-specific error codes. */
4513 struct {
4514 int errnum;
4515 char * msg;
4516 } _wsa_errlist[] = {
4517 WSAEINTR , "Interrupted function call",
4518 WSAEBADF , "Bad file descriptor",
4519 WSAEACCES , "Permission denied",
4520 WSAEFAULT , "Bad address",
4521 WSAEINVAL , "Invalid argument",
4522 WSAEMFILE , "Too many open files",
4523
4524 WSAEWOULDBLOCK , "Resource temporarily unavailable",
4525 WSAEINPROGRESS , "Operation now in progress",
4526 WSAEALREADY , "Operation already in progress",
4527 WSAENOTSOCK , "Socket operation on non-socket",
4528 WSAEDESTADDRREQ , "Destination address required",
4529 WSAEMSGSIZE , "Message too long",
4530 WSAEPROTOTYPE , "Protocol wrong type for socket",
4531 WSAENOPROTOOPT , "Bad protocol option",
4532 WSAEPROTONOSUPPORT , "Protocol not supported",
4533 WSAESOCKTNOSUPPORT , "Socket type not supported",
4534 WSAEOPNOTSUPP , "Operation not supported",
4535 WSAEPFNOSUPPORT , "Protocol family not supported",
4536 WSAEAFNOSUPPORT , "Address family not supported by protocol family",
4537 WSAEADDRINUSE , "Address already in use",
4538 WSAEADDRNOTAVAIL , "Cannot assign requested address",
4539 WSAENETDOWN , "Network is down",
4540 WSAENETUNREACH , "Network is unreachable",
4541 WSAENETRESET , "Network dropped connection on reset",
4542 WSAECONNABORTED , "Software caused connection abort",
4543 WSAECONNRESET , "Connection reset by peer",
4544 WSAENOBUFS , "No buffer space available",
4545 WSAEISCONN , "Socket is already connected",
4546 WSAENOTCONN , "Socket is not connected",
4547 WSAESHUTDOWN , "Cannot send after socket shutdown",
4548 WSAETOOMANYREFS , "Too many references", /* not sure */
4549 WSAETIMEDOUT , "Connection timed out",
4550 WSAECONNREFUSED , "Connection refused",
4551 WSAELOOP , "Network loop", /* not sure */
4552 WSAENAMETOOLONG , "Name is too long",
4553 WSAEHOSTDOWN , "Host is down",
4554 WSAEHOSTUNREACH , "No route to host",
4555 WSAENOTEMPTY , "Buffer not empty", /* not sure */
4556 WSAEPROCLIM , "Too many processes",
4557 WSAEUSERS , "Too many users", /* not sure */
4558 WSAEDQUOT , "Double quote in host name", /* really not sure */
4559 WSAESTALE , "Data is stale", /* not sure */
4560 WSAEREMOTE , "Remote error", /* not sure */
4561
4562 WSASYSNOTREADY , "Network subsystem is unavailable",
4563 WSAVERNOTSUPPORTED , "WINSOCK.DLL version out of range",
4564 WSANOTINITIALISED , "Winsock not initialized successfully",
4565 WSAEDISCON , "Graceful shutdown in progress",
4566 #ifdef WSAENOMORE
4567 WSAENOMORE , "No more operations allowed", /* not sure */
4568 WSAECANCELLED , "Operation cancelled", /* not sure */
4569 WSAEINVALIDPROCTABLE , "Invalid procedure table from service provider",
4570 WSAEINVALIDPROVIDER , "Invalid service provider version number",
4571 WSAEPROVIDERFAILEDINIT , "Unable to initialize a service provider",
4572 WSASYSCALLFAILURE , "System call failure",
4573 WSASERVICE_NOT_FOUND , "Service not found", /* not sure */
4574 WSATYPE_NOT_FOUND , "Class type not found",
4575 WSA_E_NO_MORE , "No more resources available", /* really not sure */
4576 WSA_E_CANCELLED , "Operation already cancelled", /* really not sure */
4577 WSAEREFUSED , "Operation refused", /* not sure */
4578 #endif
4579
4580 WSAHOST_NOT_FOUND , "Host not found",
4581 WSATRY_AGAIN , "Authoritative host not found during name lookup",
4582 WSANO_RECOVERY , "Non-recoverable error during name lookup",
4583 WSANO_DATA , "Valid name, no data record of requested type",
4584
4585 -1, NULL
4586 };
4587
4588 char *
4589 sys_strerror (int error_no)
4590 {
4591 int i;
4592 static char unknown_msg[40];
4593
4594 if (error_no >= 0 && error_no < sys_nerr)
4595 return sys_errlist[error_no];
4596
4597 for (i = 0; _wsa_errlist[i].errnum >= 0; i++)
4598 if (_wsa_errlist[i].errnum == error_no)
4599 return _wsa_errlist[i].msg;
4600
4601 sprintf (unknown_msg, "Unidentified error: %d", error_no);
4602 return unknown_msg;
4603 }
4604
4605 /* [andrewi 3-May-96] I've had conflicting results using both methods,
4606 but I believe the method of keeping the socket handle separate (and
4607 insuring it is not inheritable) is the correct one. */
4608
4609 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
4610
4611 static int socket_to_fd (SOCKET s);
4612
4613 int
4614 sys_socket (int af, int type, int protocol)
4615 {
4616 SOCKET s;
4617
4618 if (winsock_lib == NULL)
4619 {
4620 h_errno = ENETDOWN;
4621 return INVALID_SOCKET;
4622 }
4623
4624 check_errno ();
4625
4626 /* call the real socket function */
4627 s = pfn_socket (af, type, protocol);
4628
4629 if (s != INVALID_SOCKET)
4630 return socket_to_fd (s);
4631
4632 set_errno ();
4633 return -1;
4634 }
4635
4636 /* Convert a SOCKET to a file descriptor. */
4637 static int
4638 socket_to_fd (SOCKET s)
4639 {
4640 int fd;
4641 child_process * cp;
4642
4643 /* Although under NT 3.5 _open_osfhandle will accept a socket
4644 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
4645 that does not work under NT 3.1. However, we can get the same
4646 effect by using a backdoor function to replace an existing
4647 descriptor handle with the one we want. */
4648
4649 /* allocate a file descriptor (with appropriate flags) */
4650 fd = _open ("NUL:", _O_RDWR);
4651 if (fd >= 0)
4652 {
4653 /* Make a non-inheritable copy of the socket handle. Note
4654 that it is possible that sockets aren't actually kernel
4655 handles, which appears to be the case on Windows 9x when
4656 the MS Proxy winsock client is installed. */
4657 {
4658 /* Apparently there is a bug in NT 3.51 with some service
4659 packs, which prevents using DuplicateHandle to make a
4660 socket handle non-inheritable (causes WSACleanup to
4661 hang). The work-around is to use SetHandleInformation
4662 instead if it is available and implemented. */
4663 if (pfn_SetHandleInformation)
4664 {
4665 pfn_SetHandleInformation ((HANDLE) s, HANDLE_FLAG_INHERIT, 0);
4666 }
4667 else
4668 {
4669 HANDLE parent = GetCurrentProcess ();
4670 HANDLE new_s = INVALID_HANDLE_VALUE;
4671
4672 if (DuplicateHandle (parent,
4673 (HANDLE) s,
4674 parent,
4675 &new_s,
4676 0,
4677 FALSE,
4678 DUPLICATE_SAME_ACCESS))
4679 {
4680 /* It is possible that DuplicateHandle succeeds even
4681 though the socket wasn't really a kernel handle,
4682 because a real handle has the same value. So
4683 test whether the new handle really is a socket. */
4684 long nonblocking = 0;
4685 if (pfn_ioctlsocket ((SOCKET) new_s, FIONBIO, &nonblocking) == 0)
4686 {
4687 pfn_closesocket (s);
4688 s = (SOCKET) new_s;
4689 }
4690 else
4691 {
4692 CloseHandle (new_s);
4693 }
4694 }
4695 }
4696 }
4697 fd_info[fd].hnd = (HANDLE) s;
4698
4699 /* set our own internal flags */
4700 fd_info[fd].flags = FILE_SOCKET | FILE_BINARY | FILE_READ | FILE_WRITE;
4701
4702 cp = new_child ();
4703 if (cp)
4704 {
4705 cp->fd = fd;
4706 cp->status = STATUS_READ_ACKNOWLEDGED;
4707
4708 /* attach child_process to fd_info */
4709 if (fd_info[ fd ].cp != NULL)
4710 {
4711 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd));
4712 abort ();
4713 }
4714
4715 fd_info[ fd ].cp = cp;
4716
4717 /* success! */
4718 winsock_inuse++; /* count open sockets */
4719 return fd;
4720 }
4721
4722 /* clean up */
4723 _close (fd);
4724 }
4725 pfn_closesocket (s);
4726 h_errno = EMFILE;
4727 return -1;
4728 }
4729
4730 int
4731 sys_bind (int s, const struct sockaddr * addr, int namelen)
4732 {
4733 if (winsock_lib == NULL)
4734 {
4735 h_errno = ENOTSOCK;
4736 return SOCKET_ERROR;
4737 }
4738
4739 check_errno ();
4740 if (fd_info[s].flags & FILE_SOCKET)
4741 {
4742 int rc = pfn_bind (SOCK_HANDLE (s), addr, namelen);
4743 if (rc == SOCKET_ERROR)
4744 set_errno ();
4745 return rc;
4746 }
4747 h_errno = ENOTSOCK;
4748 return SOCKET_ERROR;
4749 }
4750
4751 int
4752 sys_connect (int s, const struct sockaddr * name, int namelen)
4753 {
4754 if (winsock_lib == NULL)
4755 {
4756 h_errno = ENOTSOCK;
4757 return SOCKET_ERROR;
4758 }
4759
4760 check_errno ();
4761 if (fd_info[s].flags & FILE_SOCKET)
4762 {
4763 int rc = pfn_connect (SOCK_HANDLE (s), name, namelen);
4764 if (rc == SOCKET_ERROR)
4765 set_errno ();
4766 return rc;
4767 }
4768 h_errno = ENOTSOCK;
4769 return SOCKET_ERROR;
4770 }
4771
4772 u_short
4773 sys_htons (u_short hostshort)
4774 {
4775 return (winsock_lib != NULL) ?
4776 pfn_htons (hostshort) : hostshort;
4777 }
4778
4779 u_short
4780 sys_ntohs (u_short netshort)
4781 {
4782 return (winsock_lib != NULL) ?
4783 pfn_ntohs (netshort) : netshort;
4784 }
4785
4786 unsigned long
4787 sys_inet_addr (const char * cp)
4788 {
4789 return (winsock_lib != NULL) ?
4790 pfn_inet_addr (cp) : INADDR_NONE;
4791 }
4792
4793 int
4794 sys_gethostname (char * name, int namelen)
4795 {
4796 if (winsock_lib != NULL)
4797 return pfn_gethostname (name, namelen);
4798
4799 if (namelen > MAX_COMPUTERNAME_LENGTH)
4800 return !GetComputerName (name, (DWORD *)&namelen);
4801
4802 h_errno = EFAULT;
4803 return SOCKET_ERROR;
4804 }
4805
4806 struct hostent *
4807 sys_gethostbyname (const char * name)
4808 {
4809 struct hostent * host;
4810
4811 if (winsock_lib == NULL)
4812 {
4813 h_errno = ENETDOWN;
4814 return NULL;
4815 }
4816
4817 check_errno ();
4818 host = pfn_gethostbyname (name);
4819 if (!host)
4820 set_errno ();
4821 return host;
4822 }
4823
4824 struct servent *
4825 sys_getservbyname (const char * name, const char * proto)
4826 {
4827 struct servent * serv;
4828
4829 if (winsock_lib == NULL)
4830 {
4831 h_errno = ENETDOWN;
4832 return NULL;
4833 }
4834
4835 check_errno ();
4836 serv = pfn_getservbyname (name, proto);
4837 if (!serv)
4838 set_errno ();
4839 return serv;
4840 }
4841
4842 int
4843 sys_getpeername (int s, struct sockaddr *addr, int * namelen)
4844 {
4845 if (winsock_lib == NULL)
4846 {
4847 h_errno = ENETDOWN;
4848 return SOCKET_ERROR;
4849 }
4850
4851 check_errno ();
4852 if (fd_info[s].flags & FILE_SOCKET)
4853 {
4854 int rc = pfn_getpeername (SOCK_HANDLE (s), addr, namelen);
4855 if (rc == SOCKET_ERROR)
4856 set_errno ();
4857 return rc;
4858 }
4859 h_errno = ENOTSOCK;
4860 return SOCKET_ERROR;
4861 }
4862
4863 int
4864 sys_shutdown (int s, int how)
4865 {
4866 if (winsock_lib == NULL)
4867 {
4868 h_errno = ENETDOWN;
4869 return SOCKET_ERROR;
4870 }
4871
4872 check_errno ();
4873 if (fd_info[s].flags & FILE_SOCKET)
4874 {
4875 int rc = pfn_shutdown (SOCK_HANDLE (s), how);
4876 if (rc == SOCKET_ERROR)
4877 set_errno ();
4878 return rc;
4879 }
4880 h_errno = ENOTSOCK;
4881 return SOCKET_ERROR;
4882 }
4883
4884 int
4885 sys_setsockopt (int s, int level, int optname, const void * optval, int optlen)
4886 {
4887 if (winsock_lib == NULL)
4888 {
4889 h_errno = ENETDOWN;
4890 return SOCKET_ERROR;
4891 }
4892
4893 check_errno ();
4894 if (fd_info[s].flags & FILE_SOCKET)
4895 {
4896 int rc = pfn_setsockopt (SOCK_HANDLE (s), level, optname,
4897 (const char *)optval, optlen);
4898 if (rc == SOCKET_ERROR)
4899 set_errno ();
4900 return rc;
4901 }
4902 h_errno = ENOTSOCK;
4903 return SOCKET_ERROR;
4904 }
4905
4906 int
4907 sys_listen (int s, int backlog)
4908 {
4909 if (winsock_lib == NULL)
4910 {
4911 h_errno = ENETDOWN;
4912 return SOCKET_ERROR;
4913 }
4914
4915 check_errno ();
4916 if (fd_info[s].flags & FILE_SOCKET)
4917 {
4918 int rc = pfn_listen (SOCK_HANDLE (s), backlog);
4919 if (rc == SOCKET_ERROR)
4920 set_errno ();
4921 else
4922 fd_info[s].flags |= FILE_LISTEN;
4923 return rc;
4924 }
4925 h_errno = ENOTSOCK;
4926 return SOCKET_ERROR;
4927 }
4928
4929 int
4930 sys_getsockname (int s, struct sockaddr * name, int * namelen)
4931 {
4932 if (winsock_lib == NULL)
4933 {
4934 h_errno = ENETDOWN;
4935 return SOCKET_ERROR;
4936 }
4937
4938 check_errno ();
4939 if (fd_info[s].flags & FILE_SOCKET)
4940 {
4941 int rc = pfn_getsockname (SOCK_HANDLE (s), name, namelen);
4942 if (rc == SOCKET_ERROR)
4943 set_errno ();
4944 return rc;
4945 }
4946 h_errno = ENOTSOCK;
4947 return SOCKET_ERROR;
4948 }
4949
4950 int
4951 sys_accept (int s, struct sockaddr * addr, int * addrlen)
4952 {
4953 if (winsock_lib == NULL)
4954 {
4955 h_errno = ENETDOWN;
4956 return -1;
4957 }
4958
4959 check_errno ();
4960 if (fd_info[s].flags & FILE_LISTEN)
4961 {
4962 SOCKET t = pfn_accept (SOCK_HANDLE (s), addr, addrlen);
4963 int fd = -1;
4964 if (t == INVALID_SOCKET)
4965 set_errno ();
4966 else
4967 fd = socket_to_fd (t);
4968
4969 fd_info[s].cp->status = STATUS_READ_ACKNOWLEDGED;
4970 ResetEvent (fd_info[s].cp->char_avail);
4971 return fd;
4972 }
4973 h_errno = ENOTSOCK;
4974 return -1;
4975 }
4976
4977 int
4978 sys_recvfrom (int s, char * buf, int len, int flags,
4979 struct sockaddr * from, int * fromlen)
4980 {
4981 if (winsock_lib == NULL)
4982 {
4983 h_errno = ENETDOWN;
4984 return SOCKET_ERROR;
4985 }
4986
4987 check_errno ();
4988 if (fd_info[s].flags & FILE_SOCKET)
4989 {
4990 int rc = pfn_recvfrom (SOCK_HANDLE (s), buf, len, flags, from, fromlen);
4991 if (rc == SOCKET_ERROR)
4992 set_errno ();
4993 return rc;
4994 }
4995 h_errno = ENOTSOCK;
4996 return SOCKET_ERROR;
4997 }
4998
4999 int
5000 sys_sendto (int s, const char * buf, int len, int flags,
5001 const struct sockaddr * to, int tolen)
5002 {
5003 if (winsock_lib == NULL)
5004 {
5005 h_errno = ENETDOWN;
5006 return SOCKET_ERROR;
5007 }
5008
5009 check_errno ();
5010 if (fd_info[s].flags & FILE_SOCKET)
5011 {
5012 int rc = pfn_sendto (SOCK_HANDLE (s), buf, len, flags, to, tolen);
5013 if (rc == SOCKET_ERROR)
5014 set_errno ();
5015 return rc;
5016 }
5017 h_errno = ENOTSOCK;
5018 return SOCKET_ERROR;
5019 }
5020
5021 /* Windows does not have an fcntl function. Provide an implementation
5022 solely for making sockets non-blocking. */
5023 int
5024 fcntl (int s, int cmd, int options)
5025 {
5026 if (winsock_lib == NULL)
5027 {
5028 h_errno = ENETDOWN;
5029 return -1;
5030 }
5031
5032 check_errno ();
5033 if (fd_info[s].flags & FILE_SOCKET)
5034 {
5035 if (cmd == F_SETFL && options == O_NDELAY)
5036 {
5037 unsigned long nblock = 1;
5038 int rc = pfn_ioctlsocket (SOCK_HANDLE (s), FIONBIO, &nblock);
5039 if (rc == SOCKET_ERROR)
5040 set_errno ();
5041 /* Keep track of the fact that we set this to non-blocking. */
5042 fd_info[s].flags |= FILE_NDELAY;
5043 return rc;
5044 }
5045 else
5046 {
5047 h_errno = EINVAL;
5048 return SOCKET_ERROR;
5049 }
5050 }
5051 h_errno = ENOTSOCK;
5052 return SOCKET_ERROR;
5053 }
5054
5055
5056 /* Shadow main io functions: we need to handle pipes and sockets more
5057 intelligently, and implement non-blocking mode as well. */
5058
5059 int
5060 sys_close (int fd)
5061 {
5062 int rc;
5063
5064 if (fd < 0)
5065 {
5066 errno = EBADF;
5067 return -1;
5068 }
5069
5070 if (fd < MAXDESC && fd_info[fd].cp)
5071 {
5072 child_process * cp = fd_info[fd].cp;
5073
5074 fd_info[fd].cp = NULL;
5075
5076 if (CHILD_ACTIVE (cp))
5077 {
5078 /* if last descriptor to active child_process then cleanup */
5079 int i;
5080 for (i = 0; i < MAXDESC; i++)
5081 {
5082 if (i == fd)
5083 continue;
5084 if (fd_info[i].cp == cp)
5085 break;
5086 }
5087 if (i == MAXDESC)
5088 {
5089 if (fd_info[fd].flags & FILE_SOCKET)
5090 {
5091 if (winsock_lib == NULL) abort ();
5092
5093 pfn_shutdown (SOCK_HANDLE (fd), 2);
5094 rc = pfn_closesocket (SOCK_HANDLE (fd));
5095
5096 winsock_inuse--; /* count open sockets */
5097 }
5098 delete_child (cp);
5099 }
5100 }
5101 }
5102
5103 /* Note that sockets do not need special treatment here (at least on
5104 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
5105 closesocket is equivalent to CloseHandle, which is to be expected
5106 because socket handles are fully fledged kernel handles. */
5107 rc = _close (fd);
5108
5109 if (rc == 0 && fd < MAXDESC)
5110 fd_info[fd].flags = 0;
5111
5112 return rc;
5113 }
5114
5115 int
5116 sys_dup (int fd)
5117 {
5118 int new_fd;
5119
5120 new_fd = _dup (fd);
5121 if (new_fd >= 0 && new_fd < MAXDESC)
5122 {
5123 /* duplicate our internal info as well */
5124 fd_info[new_fd] = fd_info[fd];
5125 }
5126 return new_fd;
5127 }
5128
5129 int
5130 sys_dup2 (int src, int dst)
5131 {
5132 int rc;
5133
5134 if (dst < 0 || dst >= MAXDESC)
5135 {
5136 errno = EBADF;
5137 return -1;
5138 }
5139
5140 /* make sure we close the destination first if it's a pipe or socket */
5141 if (src != dst && fd_info[dst].flags != 0)
5142 sys_close (dst);
5143
5144 rc = _dup2 (src, dst);
5145 if (rc == 0)
5146 {
5147 /* duplicate our internal info as well */
5148 fd_info[dst] = fd_info[src];
5149 }
5150 return rc;
5151 }
5152
5153 /* Unix pipe() has only one arg */
5154 int
5155 sys_pipe (int * phandles)
5156 {
5157 int rc;
5158 unsigned flags;
5159
5160 /* make pipe handles non-inheritable; when we spawn a child, we
5161 replace the relevant handle with an inheritable one. Also put
5162 pipes into binary mode; we will do text mode translation ourselves
5163 if required. */
5164 rc = _pipe (phandles, 0, _O_NOINHERIT | _O_BINARY);
5165
5166 if (rc == 0)
5167 {
5168 /* Protect against overflow, since Windows can open more handles than
5169 our fd_info array has room for. */
5170 if (phandles[0] >= MAXDESC || phandles[1] >= MAXDESC)
5171 {
5172 _close (phandles[0]);
5173 _close (phandles[1]);
5174 rc = -1;
5175 }
5176 else
5177 {
5178 flags = FILE_PIPE | FILE_READ | FILE_BINARY;
5179 fd_info[phandles[0]].flags = flags;
5180
5181 flags = FILE_PIPE | FILE_WRITE | FILE_BINARY;
5182 fd_info[phandles[1]].flags = flags;
5183 }
5184 }
5185
5186 return rc;
5187 }
5188
5189 /* From ntproc.c */
5190 extern int w32_pipe_read_delay;
5191
5192 /* Function to do blocking read of one byte, needed to implement
5193 select. It is only allowed on sockets and pipes. */
5194 int
5195 _sys_read_ahead (int fd)
5196 {
5197 child_process * cp;
5198 int rc;
5199
5200 if (fd < 0 || fd >= MAXDESC)
5201 return STATUS_READ_ERROR;
5202
5203 cp = fd_info[fd].cp;
5204
5205 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
5206 return STATUS_READ_ERROR;
5207
5208 if ((fd_info[fd].flags & (FILE_PIPE | FILE_SERIAL | FILE_SOCKET)) == 0
5209 || (fd_info[fd].flags & FILE_READ) == 0)
5210 {
5211 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd));
5212 abort ();
5213 }
5214
5215 cp->status = STATUS_READ_IN_PROGRESS;
5216
5217 if (fd_info[fd].flags & FILE_PIPE)
5218 {
5219 rc = _read (fd, &cp->chr, sizeof (char));
5220
5221 /* Give subprocess time to buffer some more output for us before
5222 reporting that input is available; we need this because Windows 95
5223 connects DOS programs to pipes by making the pipe appear to be
5224 the normal console stdout - as a result most DOS programs will
5225 write to stdout without buffering, ie. one character at a
5226 time. Even some W32 programs do this - "dir" in a command
5227 shell on NT is very slow if we don't do this. */
5228 if (rc > 0)
5229 {
5230 int wait = w32_pipe_read_delay;
5231
5232 if (wait > 0)
5233 Sleep (wait);
5234 else if (wait < 0)
5235 while (++wait <= 0)
5236 /* Yield remainder of our time slice, effectively giving a
5237 temporary priority boost to the child process. */
5238 Sleep (0);
5239 }
5240 }
5241 else if (fd_info[fd].flags & FILE_SERIAL)
5242 {
5243 HANDLE hnd = fd_info[fd].hnd;
5244 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
5245 COMMTIMEOUTS ct;
5246
5247 /* Configure timeouts for blocking read. */
5248 if (!GetCommTimeouts (hnd, &ct))
5249 return STATUS_READ_ERROR;
5250 ct.ReadIntervalTimeout = 0;
5251 ct.ReadTotalTimeoutMultiplier = 0;
5252 ct.ReadTotalTimeoutConstant = 0;
5253 if (!SetCommTimeouts (hnd, &ct))
5254 return STATUS_READ_ERROR;
5255
5256 if (!ReadFile (hnd, &cp->chr, sizeof (char), (DWORD*) &rc, ovl))
5257 {
5258 if (GetLastError () != ERROR_IO_PENDING)
5259 return STATUS_READ_ERROR;
5260 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
5261 return STATUS_READ_ERROR;
5262 }
5263 }
5264 else if (fd_info[fd].flags & FILE_SOCKET)
5265 {
5266 unsigned long nblock = 0;
5267 /* We always want this to block, so temporarily disable NDELAY. */
5268 if (fd_info[fd].flags & FILE_NDELAY)
5269 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
5270
5271 rc = pfn_recv (SOCK_HANDLE (fd), &cp->chr, sizeof (char), 0);
5272
5273 if (fd_info[fd].flags & FILE_NDELAY)
5274 {
5275 nblock = 1;
5276 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
5277 }
5278 }
5279
5280 if (rc == sizeof (char))
5281 cp->status = STATUS_READ_SUCCEEDED;
5282 else
5283 cp->status = STATUS_READ_FAILED;
5284
5285 return cp->status;
5286 }
5287
5288 int
5289 _sys_wait_accept (int fd)
5290 {
5291 HANDLE hEv;
5292 child_process * cp;
5293 int rc;
5294
5295 if (fd < 0 || fd >= MAXDESC)
5296 return STATUS_READ_ERROR;
5297
5298 cp = fd_info[fd].cp;
5299
5300 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
5301 return STATUS_READ_ERROR;
5302
5303 cp->status = STATUS_READ_FAILED;
5304
5305 hEv = pfn_WSACreateEvent ();
5306 rc = pfn_WSAEventSelect (SOCK_HANDLE (fd), hEv, FD_ACCEPT);
5307 if (rc != SOCKET_ERROR)
5308 {
5309 rc = WaitForSingleObject (hEv, INFINITE);
5310 pfn_WSAEventSelect (SOCK_HANDLE (fd), NULL, 0);
5311 if (rc == WAIT_OBJECT_0)
5312 cp->status = STATUS_READ_SUCCEEDED;
5313 }
5314 pfn_WSACloseEvent (hEv);
5315
5316 return cp->status;
5317 }
5318
5319 int
5320 sys_read (int fd, char * buffer, unsigned int count)
5321 {
5322 int nchars;
5323 int to_read;
5324 DWORD waiting;
5325 char * orig_buffer = buffer;
5326
5327 if (fd < 0)
5328 {
5329 errno = EBADF;
5330 return -1;
5331 }
5332
5333 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
5334 {
5335 child_process *cp = fd_info[fd].cp;
5336
5337 if ((fd_info[fd].flags & FILE_READ) == 0)
5338 {
5339 errno = EBADF;
5340 return -1;
5341 }
5342
5343 nchars = 0;
5344
5345 /* re-read CR carried over from last read */
5346 if (fd_info[fd].flags & FILE_LAST_CR)
5347 {
5348 if (fd_info[fd].flags & FILE_BINARY) abort ();
5349 *buffer++ = 0x0d;
5350 count--;
5351 nchars++;
5352 fd_info[fd].flags &= ~FILE_LAST_CR;
5353 }
5354
5355 /* presence of a child_process structure means we are operating in
5356 non-blocking mode - otherwise we just call _read directly.
5357 Note that the child_process structure might be missing because
5358 reap_subprocess has been called; in this case the pipe is
5359 already broken, so calling _read on it is okay. */
5360 if (cp)
5361 {
5362 int current_status = cp->status;
5363
5364 switch (current_status)
5365 {
5366 case STATUS_READ_FAILED:
5367 case STATUS_READ_ERROR:
5368 /* report normal EOF if nothing in buffer */
5369 if (nchars <= 0)
5370 fd_info[fd].flags |= FILE_AT_EOF;
5371 return nchars;
5372
5373 case STATUS_READ_READY:
5374 case STATUS_READ_IN_PROGRESS:
5375 DebPrint (("sys_read called when read is in progress\n"));
5376 errno = EWOULDBLOCK;
5377 return -1;
5378
5379 case STATUS_READ_SUCCEEDED:
5380 /* consume read-ahead char */
5381 *buffer++ = cp->chr;
5382 count--;
5383 nchars++;
5384 cp->status = STATUS_READ_ACKNOWLEDGED;
5385 ResetEvent (cp->char_avail);
5386
5387 case STATUS_READ_ACKNOWLEDGED:
5388 break;
5389
5390 default:
5391 DebPrint (("sys_read: bad status %d\n", current_status));
5392 errno = EBADF;
5393 return -1;
5394 }
5395
5396 if (fd_info[fd].flags & FILE_PIPE)
5397 {
5398 PeekNamedPipe ((HANDLE) _get_osfhandle (fd), NULL, 0, NULL, &waiting, NULL);
5399 to_read = min (waiting, (DWORD) count);
5400
5401 if (to_read > 0)
5402 nchars += _read (fd, buffer, to_read);
5403 }
5404 else if (fd_info[fd].flags & FILE_SERIAL)
5405 {
5406 HANDLE hnd = fd_info[fd].hnd;
5407 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
5408 DWORD err = 0;
5409 int rc = 0;
5410 COMMTIMEOUTS ct;
5411
5412 if (count > 0)
5413 {
5414 /* Configure timeouts for non-blocking read. */
5415 if (!GetCommTimeouts (hnd, &ct))
5416 {
5417 errno = EIO;
5418 return -1;
5419 }
5420 ct.ReadIntervalTimeout = MAXDWORD;
5421 ct.ReadTotalTimeoutMultiplier = 0;
5422 ct.ReadTotalTimeoutConstant = 0;
5423 if (!SetCommTimeouts (hnd, &ct))
5424 {
5425 errno = EIO;
5426 return -1;
5427 }
5428
5429 if (!ResetEvent (ovl->hEvent))
5430 {
5431 errno = EIO;
5432 return -1;
5433 }
5434 if (!ReadFile (hnd, buffer, count, (DWORD*) &rc, ovl))
5435 {
5436 if (GetLastError () != ERROR_IO_PENDING)
5437 {
5438 errno = EIO;
5439 return -1;
5440 }
5441 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
5442 {
5443 errno = EIO;
5444 return -1;
5445 }
5446 }
5447 nchars += rc;
5448 }
5449 }
5450 else /* FILE_SOCKET */
5451 {
5452 if (winsock_lib == NULL) abort ();
5453
5454 /* do the equivalent of a non-blocking read */
5455 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONREAD, &waiting);
5456 if (waiting == 0 && nchars == 0)
5457 {
5458 h_errno = errno = EWOULDBLOCK;
5459 return -1;
5460 }
5461
5462 if (waiting)
5463 {
5464 /* always use binary mode for sockets */
5465 int res = pfn_recv (SOCK_HANDLE (fd), buffer, count, 0);
5466 if (res == SOCKET_ERROR)
5467 {
5468 DebPrint (("sys_read.recv failed with error %d on socket %ld\n",
5469 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
5470 set_errno ();
5471 return -1;
5472 }
5473 nchars += res;
5474 }
5475 }
5476 }
5477 else
5478 {
5479 int nread = _read (fd, buffer, count);
5480 if (nread >= 0)
5481 nchars += nread;
5482 else if (nchars == 0)
5483 nchars = nread;
5484 }
5485
5486 if (nchars <= 0)
5487 fd_info[fd].flags |= FILE_AT_EOF;
5488 /* Perform text mode translation if required. */
5489 else if ((fd_info[fd].flags & FILE_BINARY) == 0)
5490 {
5491 nchars = crlf_to_lf (nchars, orig_buffer);
5492 /* If buffer contains only CR, return that. To be absolutely
5493 sure we should attempt to read the next char, but in
5494 practice a CR to be followed by LF would not appear by
5495 itself in the buffer. */
5496 if (nchars > 1 && orig_buffer[nchars - 1] == 0x0d)
5497 {
5498 fd_info[fd].flags |= FILE_LAST_CR;
5499 nchars--;
5500 }
5501 }
5502 }
5503 else
5504 nchars = _read (fd, buffer, count);
5505
5506 return nchars;
5507 }
5508
5509 /* From w32xfns.c */
5510 extern HANDLE interrupt_handle;
5511
5512 /* For now, don't bother with a non-blocking mode */
5513 int
5514 sys_write (int fd, const void * buffer, unsigned int count)
5515 {
5516 int nchars;
5517
5518 if (fd < 0)
5519 {
5520 errno = EBADF;
5521 return -1;
5522 }
5523
5524 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
5525 {
5526 if ((fd_info[fd].flags & FILE_WRITE) == 0)
5527 {
5528 errno = EBADF;
5529 return -1;
5530 }
5531
5532 /* Perform text mode translation if required. */
5533 if ((fd_info[fd].flags & FILE_BINARY) == 0)
5534 {
5535 char * tmpbuf = alloca (count * 2);
5536 unsigned char * src = (void *)buffer;
5537 unsigned char * dst = tmpbuf;
5538 int nbytes = count;
5539
5540 while (1)
5541 {
5542 unsigned char *next;
5543 /* copy next line or remaining bytes */
5544 next = _memccpy (dst, src, '\n', nbytes);
5545 if (next)
5546 {
5547 /* copied one line ending with '\n' */
5548 int copied = next - dst;
5549 nbytes -= copied;
5550 src += copied;
5551 /* insert '\r' before '\n' */
5552 next[-1] = '\r';
5553 next[0] = '\n';
5554 dst = next + 1;
5555 count++;
5556 }
5557 else
5558 /* copied remaining partial line -> now finished */
5559 break;
5560 }
5561 buffer = tmpbuf;
5562 }
5563 }
5564
5565 if (fd < MAXDESC && fd_info[fd].flags & FILE_SERIAL)
5566 {
5567 HANDLE hnd = (HANDLE) _get_osfhandle (fd);
5568 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_write;
5569 HANDLE wait_hnd[2] = { interrupt_handle, ovl->hEvent };
5570 DWORD active = 0;
5571
5572 if (!WriteFile (hnd, buffer, count, (DWORD*) &nchars, ovl))
5573 {
5574 if (GetLastError () != ERROR_IO_PENDING)
5575 {
5576 errno = EIO;
5577 return -1;
5578 }
5579 if (detect_input_pending ())
5580 active = MsgWaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE,
5581 QS_ALLINPUT);
5582 else
5583 active = WaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE);
5584 if (active == WAIT_OBJECT_0)
5585 { /* User pressed C-g, cancel write, then leave. Don't bother
5586 cleaning up as we may only get stuck in buggy drivers. */
5587 PurgeComm (hnd, PURGE_TXABORT | PURGE_TXCLEAR);
5588 CancelIo (hnd);
5589 errno = EIO;
5590 return -1;
5591 }
5592 if (active == WAIT_OBJECT_0 + 1
5593 && !GetOverlappedResult (hnd, ovl, (DWORD*) &nchars, TRUE))
5594 {
5595 errno = EIO;
5596 return -1;
5597 }
5598 }
5599 }
5600 else if (fd < MAXDESC && fd_info[fd].flags & FILE_SOCKET)
5601 {
5602 unsigned long nblock = 0;
5603 if (winsock_lib == NULL) abort ();
5604
5605 /* TODO: implement select() properly so non-blocking I/O works. */
5606 /* For now, make sure the write blocks. */
5607 if (fd_info[fd].flags & FILE_NDELAY)
5608 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
5609
5610 nchars = pfn_send (SOCK_HANDLE (fd), buffer, count, 0);
5611
5612 /* Set the socket back to non-blocking if it was before,
5613 for other operations that support it. */
5614 if (fd_info[fd].flags & FILE_NDELAY)
5615 {
5616 nblock = 1;
5617 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
5618 }
5619
5620 if (nchars == SOCKET_ERROR)
5621 {
5622 DebPrint (("sys_write.send failed with error %d on socket %ld\n",
5623 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
5624 set_errno ();
5625 }
5626 }
5627 else
5628 {
5629 /* Some networked filesystems don't like too large writes, so
5630 break them into smaller chunks. See the Comments section of
5631 the MSDN documentation of WriteFile for details behind the
5632 choice of the value of CHUNK below. See also the thread
5633 http://thread.gmane.org/gmane.comp.version-control.git/145294
5634 in the git mailing list. */
5635 const unsigned char *p = buffer;
5636 const unsigned chunk = 30 * 1024 * 1024;
5637
5638 nchars = 0;
5639 while (count > 0)
5640 {
5641 unsigned this_chunk = count < chunk ? count : chunk;
5642 int n = _write (fd, p, this_chunk);
5643
5644 nchars += n;
5645 if (n < 0)
5646 {
5647 nchars = n;
5648 break;
5649 }
5650 else if (n < this_chunk)
5651 break;
5652 count -= n;
5653 p += n;
5654 }
5655 }
5656
5657 return nchars;
5658 }
5659
5660 static void
5661 check_windows_init_file (void)
5662 {
5663 extern int noninteractive, inhibit_window_system;
5664
5665 /* A common indication that Emacs is not installed properly is when
5666 it cannot find the Windows installation file. If this file does
5667 not exist in the expected place, tell the user. */
5668
5669 if (!noninteractive && !inhibit_window_system)
5670 {
5671 extern Lisp_Object Vwindow_system, Vload_path, Qfile_exists_p;
5672 Lisp_Object objs[2];
5673 Lisp_Object full_load_path;
5674 Lisp_Object init_file;
5675 int fd;
5676
5677 objs[0] = Vload_path;
5678 objs[1] = decode_env_path (0, (getenv ("EMACSLOADPATH")));
5679 full_load_path = Fappend (2, objs);
5680 init_file = build_string ("term/w32-win");
5681 fd = openp (full_load_path, init_file, Fget_load_suffixes (), NULL, Qnil);
5682 if (fd < 0)
5683 {
5684 Lisp_Object load_path_print = Fprin1_to_string (full_load_path, Qnil);
5685 char *init_file_name = SDATA (init_file);
5686 char *load_path = SDATA (load_path_print);
5687 char *buffer = alloca (1024
5688 + strlen (init_file_name)
5689 + strlen (load_path));
5690
5691 sprintf (buffer,
5692 "The Emacs Windows initialization file \"%s.el\" "
5693 "could not be found in your Emacs installation. "
5694 "Emacs checked the following directories for this file:\n"
5695 "\n%s\n\n"
5696 "When Emacs cannot find this file, it usually means that it "
5697 "was not installed properly, or its distribution file was "
5698 "not unpacked properly.\nSee the README.W32 file in the "
5699 "top-level Emacs directory for more information.",
5700 init_file_name, load_path);
5701 MessageBox (NULL,
5702 buffer,
5703 "Emacs Abort Dialog",
5704 MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
5705 /* Use the low-level Emacs abort. */
5706 #undef abort
5707 abort ();
5708 }
5709 else
5710 {
5711 _close (fd);
5712 }
5713 }
5714 }
5715
5716 void
5717 term_ntproc (void)
5718 {
5719 /* shutdown the socket interface if necessary */
5720 term_winsock ();
5721
5722 term_w32select ();
5723 }
5724
5725 void
5726 init_ntproc (void)
5727 {
5728 /* Initialise the socket interface now if available and requested by
5729 the user by defining PRELOAD_WINSOCK; otherwise loading will be
5730 delayed until open-network-stream is called (w32-has-winsock can
5731 also be used to dynamically load or reload winsock).
5732
5733 Conveniently, init_environment is called before us, so
5734 PRELOAD_WINSOCK can be set in the registry. */
5735
5736 /* Always initialize this correctly. */
5737 winsock_lib = NULL;
5738
5739 if (getenv ("PRELOAD_WINSOCK") != NULL)
5740 init_winsock (TRUE);
5741
5742 /* Initial preparation for subprocess support: replace our standard
5743 handles with non-inheritable versions. */
5744 {
5745 HANDLE parent;
5746 HANDLE stdin_save = INVALID_HANDLE_VALUE;
5747 HANDLE stdout_save = INVALID_HANDLE_VALUE;
5748 HANDLE stderr_save = INVALID_HANDLE_VALUE;
5749
5750 parent = GetCurrentProcess ();
5751
5752 /* ignore errors when duplicating and closing; typically the
5753 handles will be invalid when running as a gui program. */
5754 DuplicateHandle (parent,
5755 GetStdHandle (STD_INPUT_HANDLE),
5756 parent,
5757 &stdin_save,
5758 0,
5759 FALSE,
5760 DUPLICATE_SAME_ACCESS);
5761
5762 DuplicateHandle (parent,
5763 GetStdHandle (STD_OUTPUT_HANDLE),
5764 parent,
5765 &stdout_save,
5766 0,
5767 FALSE,
5768 DUPLICATE_SAME_ACCESS);
5769
5770 DuplicateHandle (parent,
5771 GetStdHandle (STD_ERROR_HANDLE),
5772 parent,
5773 &stderr_save,
5774 0,
5775 FALSE,
5776 DUPLICATE_SAME_ACCESS);
5777
5778 fclose (stdin);
5779 fclose (stdout);
5780 fclose (stderr);
5781
5782 if (stdin_save != INVALID_HANDLE_VALUE)
5783 _open_osfhandle ((long) stdin_save, O_TEXT);
5784 else
5785 _open ("nul", O_TEXT | O_NOINHERIT | O_RDONLY);
5786 _fdopen (0, "r");
5787
5788 if (stdout_save != INVALID_HANDLE_VALUE)
5789 _open_osfhandle ((long) stdout_save, O_TEXT);
5790 else
5791 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
5792 _fdopen (1, "w");
5793
5794 if (stderr_save != INVALID_HANDLE_VALUE)
5795 _open_osfhandle ((long) stderr_save, O_TEXT);
5796 else
5797 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
5798 _fdopen (2, "w");
5799 }
5800
5801 /* unfortunately, atexit depends on implementation of malloc */
5802 /* atexit (term_ntproc); */
5803 signal (SIGABRT, term_ntproc);
5804
5805 /* determine which drives are fixed, for GetCachedVolumeInformation */
5806 {
5807 /* GetDriveType must have trailing backslash. */
5808 char drive[] = "A:\\";
5809
5810 /* Loop over all possible drive letters */
5811 while (*drive <= 'Z')
5812 {
5813 /* Record if this drive letter refers to a fixed drive. */
5814 fixed_drives[DRIVE_INDEX (*drive)] =
5815 (GetDriveType (drive) == DRIVE_FIXED);
5816
5817 (*drive)++;
5818 }
5819
5820 /* Reset the volume info cache. */
5821 volume_cache = NULL;
5822 }
5823
5824 /* Check to see if Emacs has been installed correctly. */
5825 check_windows_init_file ();
5826 }
5827
5828 /*
5829 shutdown_handler ensures that buffers' autosave files are
5830 up to date when the user logs off, or the system shuts down.
5831 */
5832 static BOOL WINAPI
5833 shutdown_handler (DWORD type)
5834 {
5835 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
5836 if (type == CTRL_CLOSE_EVENT /* User closes console window. */
5837 || type == CTRL_LOGOFF_EVENT /* User logs off. */
5838 || type == CTRL_SHUTDOWN_EVENT) /* User shutsdown. */
5839 {
5840 /* Shut down cleanly, making sure autosave files are up to date. */
5841 shut_down_emacs (0, 0, Qnil);
5842 }
5843
5844 /* Allow other handlers to handle this signal. */
5845 return FALSE;
5846 }
5847
5848 /*
5849 globals_of_w32 is used to initialize those global variables that
5850 must always be initialized on startup even when the global variable
5851 initialized is non zero (see the function main in emacs.c).
5852 */
5853 void
5854 globals_of_w32 (void)
5855 {
5856 HMODULE kernel32 = GetModuleHandle ("kernel32.dll");
5857
5858 get_process_times_fn = (GetProcessTimes_Proc)
5859 GetProcAddress (kernel32, "GetProcessTimes");
5860
5861 g_b_init_is_windows_9x = 0;
5862 g_b_init_open_process_token = 0;
5863 g_b_init_get_token_information = 0;
5864 g_b_init_lookup_account_sid = 0;
5865 g_b_init_get_sid_sub_authority = 0;
5866 g_b_init_get_sid_sub_authority_count = 0;
5867 g_b_init_get_file_security = 0;
5868 g_b_init_get_security_descriptor_owner = 0;
5869 g_b_init_get_security_descriptor_group = 0;
5870 g_b_init_is_valid_sid = 0;
5871 g_b_init_create_toolhelp32_snapshot = 0;
5872 g_b_init_process32_first = 0;
5873 g_b_init_process32_next = 0;
5874 g_b_init_open_thread_token = 0;
5875 g_b_init_impersonate_self = 0;
5876 g_b_init_revert_to_self = 0;
5877 g_b_init_get_process_memory_info = 0;
5878 g_b_init_get_process_working_set_size = 0;
5879 g_b_init_global_memory_status = 0;
5880 g_b_init_global_memory_status_ex = 0;
5881 g_b_init_equal_sid = 0;
5882 g_b_init_copy_sid = 0;
5883 g_b_init_get_length_sid = 0;
5884 g_b_init_get_native_system_info = 0;
5885 g_b_init_get_system_times = 0;
5886 num_of_processors = 0;
5887 /* The following sets a handler for shutdown notifications for
5888 console apps. This actually applies to Emacs in both console and
5889 GUI modes, since we had to fool windows into thinking emacs is a
5890 console application to get console mode to work. */
5891 SetConsoleCtrlHandler (shutdown_handler, TRUE);
5892
5893 /* "None" is the default group name on standalone workstations. */
5894 strcpy (dflt_group_name, "None");
5895 }
5896
5897 /* For make-serial-process */
5898 int
5899 serial_open (char *port)
5900 {
5901 HANDLE hnd;
5902 child_process *cp;
5903 int fd = -1;
5904
5905 hnd = CreateFile (port, GENERIC_READ | GENERIC_WRITE, 0, 0,
5906 OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
5907 if (hnd == INVALID_HANDLE_VALUE)
5908 error ("Could not open %s", port);
5909 fd = (int) _open_osfhandle ((int) hnd, 0);
5910 if (fd == -1)
5911 error ("Could not open %s", port);
5912
5913 cp = new_child ();
5914 if (!cp)
5915 error ("Could not create child process");
5916 cp->fd = fd;
5917 cp->status = STATUS_READ_ACKNOWLEDGED;
5918 fd_info[ fd ].hnd = hnd;
5919 fd_info[ fd ].flags |=
5920 FILE_READ | FILE_WRITE | FILE_BINARY | FILE_SERIAL;
5921 if (fd_info[ fd ].cp != NULL)
5922 {
5923 error ("fd_info[fd = %d] is already in use", fd);
5924 }
5925 fd_info[ fd ].cp = cp;
5926 cp->ovl_read.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
5927 if (cp->ovl_read.hEvent == NULL)
5928 error ("Could not create read event");
5929 cp->ovl_write.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
5930 if (cp->ovl_write.hEvent == NULL)
5931 error ("Could not create write event");
5932
5933 return fd;
5934 }
5935
5936 /* For serial-process-configure */
5937 void
5938 serial_configure (struct Lisp_Process *p, Lisp_Object contact)
5939 {
5940 Lisp_Object childp2 = Qnil;
5941 Lisp_Object tem = Qnil;
5942 HANDLE hnd;
5943 DCB dcb;
5944 COMMTIMEOUTS ct;
5945 char summary[4] = "???"; /* This usually becomes "8N1". */
5946
5947 if ((fd_info[ p->outfd ].flags & FILE_SERIAL) == 0)
5948 error ("Not a serial process");
5949 hnd = fd_info[ p->outfd ].hnd;
5950
5951 childp2 = Fcopy_sequence (p->childp);
5952
5953 /* Initialize timeouts for blocking read and blocking write. */
5954 if (!GetCommTimeouts (hnd, &ct))
5955 error ("GetCommTimeouts() failed");
5956 ct.ReadIntervalTimeout = 0;
5957 ct.ReadTotalTimeoutMultiplier = 0;
5958 ct.ReadTotalTimeoutConstant = 0;
5959 ct.WriteTotalTimeoutMultiplier = 0;
5960 ct.WriteTotalTimeoutConstant = 0;
5961 if (!SetCommTimeouts (hnd, &ct))
5962 error ("SetCommTimeouts() failed");
5963 /* Read port attributes and prepare default configuration. */
5964 memset (&dcb, 0, sizeof (dcb));
5965 dcb.DCBlength = sizeof (DCB);
5966 if (!GetCommState (hnd, &dcb))
5967 error ("GetCommState() failed");
5968 dcb.fBinary = TRUE;
5969 dcb.fNull = FALSE;
5970 dcb.fAbortOnError = FALSE;
5971 /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
5972 dcb.ErrorChar = 0;
5973 dcb.EofChar = 0;
5974 dcb.EvtChar = 0;
5975
5976 /* Configure speed. */
5977 if (!NILP (Fplist_member (contact, QCspeed)))
5978 tem = Fplist_get (contact, QCspeed);
5979 else
5980 tem = Fplist_get (p->childp, QCspeed);
5981 CHECK_NUMBER (tem);
5982 dcb.BaudRate = XINT (tem);
5983 childp2 = Fplist_put (childp2, QCspeed, tem);
5984
5985 /* Configure bytesize. */
5986 if (!NILP (Fplist_member (contact, QCbytesize)))
5987 tem = Fplist_get (contact, QCbytesize);
5988 else
5989 tem = Fplist_get (p->childp, QCbytesize);
5990 if (NILP (tem))
5991 tem = make_number (8);
5992 CHECK_NUMBER (tem);
5993 if (XINT (tem) != 7 && XINT (tem) != 8)
5994 error (":bytesize must be nil (8), 7, or 8");
5995 dcb.ByteSize = XINT (tem);
5996 summary[0] = XINT (tem) + '0';
5997 childp2 = Fplist_put (childp2, QCbytesize, tem);
5998
5999 /* Configure parity. */
6000 if (!NILP (Fplist_member (contact, QCparity)))
6001 tem = Fplist_get (contact, QCparity);
6002 else
6003 tem = Fplist_get (p->childp, QCparity);
6004 if (!NILP (tem) && !EQ (tem, Qeven) && !EQ (tem, Qodd))
6005 error (":parity must be nil (no parity), `even', or `odd'");
6006 dcb.fParity = FALSE;
6007 dcb.Parity = NOPARITY;
6008 dcb.fErrorChar = FALSE;
6009 if (NILP (tem))
6010 {
6011 summary[1] = 'N';
6012 }
6013 else if (EQ (tem, Qeven))
6014 {
6015 summary[1] = 'E';
6016 dcb.fParity = TRUE;
6017 dcb.Parity = EVENPARITY;
6018 dcb.fErrorChar = TRUE;
6019 }
6020 else if (EQ (tem, Qodd))
6021 {
6022 summary[1] = 'O';
6023 dcb.fParity = TRUE;
6024 dcb.Parity = ODDPARITY;
6025 dcb.fErrorChar = TRUE;
6026 }
6027 childp2 = Fplist_put (childp2, QCparity, tem);
6028
6029 /* Configure stopbits. */
6030 if (!NILP (Fplist_member (contact, QCstopbits)))
6031 tem = Fplist_get (contact, QCstopbits);
6032 else
6033 tem = Fplist_get (p->childp, QCstopbits);
6034 if (NILP (tem))
6035 tem = make_number (1);
6036 CHECK_NUMBER (tem);
6037 if (XINT (tem) != 1 && XINT (tem) != 2)
6038 error (":stopbits must be nil (1 stopbit), 1, or 2");
6039 summary[2] = XINT (tem) + '0';
6040 if (XINT (tem) == 1)
6041 dcb.StopBits = ONESTOPBIT;
6042 else if (XINT (tem) == 2)
6043 dcb.StopBits = TWOSTOPBITS;
6044 childp2 = Fplist_put (childp2, QCstopbits, tem);
6045
6046 /* Configure flowcontrol. */
6047 if (!NILP (Fplist_member (contact, QCflowcontrol)))
6048 tem = Fplist_get (contact, QCflowcontrol);
6049 else
6050 tem = Fplist_get (p->childp, QCflowcontrol);
6051 if (!NILP (tem) && !EQ (tem, Qhw) && !EQ (tem, Qsw))
6052 error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
6053 dcb.fOutxCtsFlow = FALSE;
6054 dcb.fOutxDsrFlow = FALSE;
6055 dcb.fDtrControl = DTR_CONTROL_DISABLE;
6056 dcb.fDsrSensitivity = FALSE;
6057 dcb.fTXContinueOnXoff = FALSE;
6058 dcb.fOutX = FALSE;
6059 dcb.fInX = FALSE;
6060 dcb.fRtsControl = RTS_CONTROL_DISABLE;
6061 dcb.XonChar = 17; /* Control-Q */
6062 dcb.XoffChar = 19; /* Control-S */
6063 if (NILP (tem))
6064 {
6065 /* Already configured. */
6066 }
6067 else if (EQ (tem, Qhw))
6068 {
6069 dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
6070 dcb.fOutxCtsFlow = TRUE;
6071 }
6072 else if (EQ (tem, Qsw))
6073 {
6074 dcb.fOutX = TRUE;
6075 dcb.fInX = TRUE;
6076 }
6077 childp2 = Fplist_put (childp2, QCflowcontrol, tem);
6078
6079 /* Activate configuration. */
6080 if (!SetCommState (hnd, &dcb))
6081 error ("SetCommState() failed");
6082
6083 childp2 = Fplist_put (childp2, QCsummary, build_string (summary));
6084 p->childp = childp2;
6085 }
6086
6087 /* end of w32.c */
6088
6089 /* arch-tag: 90442dd3-37be-482b-b272-ac752e3049f1
6090 (do not change this comment) */