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