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