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