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