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