Start; wrote conversion from UTF-8 to UTF-16 and ANSI.
[bpt/emacs.git] / src / w32.c
1 /* Utility and Unix shadow routines for GNU Emacs on the Microsoft Windows API.
2 Copyright (C) 1994-1995, 2000-2013 Free Software Foundation, Inc.
3
4 This file is part of GNU Emacs.
5
6 GNU Emacs is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
18
19 /*
20 Geoff Voelker (voelker@cs.washington.edu) 7-29-94
21 */
22
23 #include <mingw_time.h>
24 #include <stddef.h> /* for offsetof */
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <float.h> /* for DBL_EPSILON */
28 #include <io.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <ctype.h>
32 #include <signal.h>
33 #include <sys/file.h>
34 #include <time.h> /* must be before nt/inc/sys/time.h, for MinGW64 */
35 #include <sys/time.h>
36 #include <sys/utime.h>
37 #include <math.h>
38
39 /* must include CRT headers *before* config.h */
40
41 #include <config.h>
42 #include <mbstring.h> /* for _mbspbrk, _mbslwr, _mbsrchr, ... */
43
44 #undef access
45 #undef chdir
46 #undef chmod
47 #undef creat
48 #undef ctime
49 #undef fopen
50 #undef link
51 #undef mkdir
52 #undef open
53 #undef rename
54 #undef rmdir
55 #undef unlink
56
57 #undef close
58 #undef dup
59 #undef dup2
60 #undef pipe
61 #undef read
62 #undef write
63
64 #undef strerror
65
66 #undef localtime
67
68 #include "lisp.h"
69 #include "epaths.h" /* for SHELL */
70
71 #include <pwd.h>
72 #include <grp.h>
73
74 /* MinGW64 (_W64) defines these in its _mingw.h. */
75 #if defined(__GNUC__) && !defined(_W64)
76 #define _ANONYMOUS_UNION
77 #define _ANONYMOUS_STRUCT
78 #endif
79 #include <windows.h>
80 /* Some versions of compiler define MEMORYSTATUSEX, some don't, so we
81 use a different name to avoid compilation problems. */
82 typedef struct _MEMORY_STATUS_EX {
83 DWORD dwLength;
84 DWORD dwMemoryLoad;
85 DWORDLONG ullTotalPhys;
86 DWORDLONG ullAvailPhys;
87 DWORDLONG ullTotalPageFile;
88 DWORDLONG ullAvailPageFile;
89 DWORDLONG ullTotalVirtual;
90 DWORDLONG ullAvailVirtual;
91 DWORDLONG ullAvailExtendedVirtual;
92 } MEMORY_STATUS_EX,*LPMEMORY_STATUS_EX;
93
94 /* These are here so that GDB would know about these data types. This
95 allows to attach GDB to Emacs when a fatal exception is triggered
96 and Windows pops up the "application needs to be closed" dialog.
97 At that point, _gnu_exception_handler, the top-level exception
98 handler installed by the MinGW startup code, is somewhere on the
99 call-stack of the main thread, so going to that call frame and
100 looking at the argument to _gnu_exception_handler, which is a
101 PEXCEPTION_POINTERS pointer, can reveal the exception code
102 (excptr->ExceptionRecord->ExceptionCode) and the address where the
103 exception happened (excptr->ExceptionRecord->ExceptionAddress), as
104 well as some additional information specific to the exception. */
105 PEXCEPTION_POINTERS excptr;
106 PEXCEPTION_RECORD excprec;
107 PCONTEXT ctxrec;
108
109 #include <lmcons.h>
110 #include <shlobj.h>
111
112 #include <tlhelp32.h>
113 #include <psapi.h>
114 #ifndef _MSC_VER
115 #include <w32api.h>
116 #endif
117 #if _WIN32_WINNT < 0x0500
118 #if !defined (__MINGW32__) || __W32API_MAJOR_VERSION < 3 || (__W32API_MAJOR_VERSION == 3 && __W32API_MINOR_VERSION < 15)
119 /* This either is not in psapi.h or guarded by higher value of
120 _WIN32_WINNT than what we use. w32api supplied with MinGW 3.15
121 defines it in psapi.h */
122 typedef struct _PROCESS_MEMORY_COUNTERS_EX {
123 DWORD cb;
124 DWORD PageFaultCount;
125 SIZE_T PeakWorkingSetSize;
126 SIZE_T WorkingSetSize;
127 SIZE_T QuotaPeakPagedPoolUsage;
128 SIZE_T QuotaPagedPoolUsage;
129 SIZE_T QuotaPeakNonPagedPoolUsage;
130 SIZE_T QuotaNonPagedPoolUsage;
131 SIZE_T PagefileUsage;
132 SIZE_T PeakPagefileUsage;
133 SIZE_T PrivateUsage;
134 } PROCESS_MEMORY_COUNTERS_EX,*PPROCESS_MEMORY_COUNTERS_EX;
135 #endif
136 #endif
137
138 #include <winioctl.h>
139 #include <aclapi.h>
140 #include <sddl.h>
141
142 #include <sys/acl.h>
143
144 /* This is not in MinGW's sddl.h (but they are in MSVC headers), so we
145 define them by hand if not already defined. */
146 #ifndef SDDL_REVISION_1
147 #define SDDL_REVISION_1 1
148 #endif /* SDDL_REVISION_1 */
149
150 #if defined(_MSC_VER) || defined(_W64)
151 /* MSVC and MinGW64 don't provide the definition of
152 REPARSE_DATA_BUFFER and the associated macros, except on ntifs.h,
153 which cannot be included because it triggers conflicts with other
154 Windows API headers. So we define it here by hand. */
155
156 typedef struct _REPARSE_DATA_BUFFER {
157 ULONG ReparseTag;
158 USHORT ReparseDataLength;
159 USHORT Reserved;
160 union {
161 struct {
162 USHORT SubstituteNameOffset;
163 USHORT SubstituteNameLength;
164 USHORT PrintNameOffset;
165 USHORT PrintNameLength;
166 ULONG Flags;
167 WCHAR PathBuffer[1];
168 } SymbolicLinkReparseBuffer;
169 struct {
170 USHORT SubstituteNameOffset;
171 USHORT SubstituteNameLength;
172 USHORT PrintNameOffset;
173 USHORT PrintNameLength;
174 WCHAR PathBuffer[1];
175 } MountPointReparseBuffer;
176 struct {
177 UCHAR DataBuffer[1];
178 } GenericReparseBuffer;
179 } DUMMYUNIONNAME;
180 } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
181
182 #ifndef FILE_DEVICE_FILE_SYSTEM
183 #define FILE_DEVICE_FILE_SYSTEM 9
184 #endif
185 #ifndef METHOD_BUFFERED
186 #define METHOD_BUFFERED 0
187 #endif
188 #ifndef FILE_ANY_ACCESS
189 #define FILE_ANY_ACCESS 0x00000000
190 #endif
191 #ifndef CTL_CODE
192 #define CTL_CODE(t,f,m,a) (((t)<<16)|((a)<<14)|((f)<<2)|(m))
193 #endif
194 /* MinGW64 defines FSCTL_GET_REPARSE_POINT on winioctl.h. */
195 #ifndef FSCTL_GET_REPARSE_POINT
196 #define FSCTL_GET_REPARSE_POINT \
197 CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS)
198 #endif
199 #endif
200
201 /* TCP connection support. */
202 #include <sys/socket.h>
203 #undef socket
204 #undef bind
205 #undef connect
206 #undef htons
207 #undef ntohs
208 #undef inet_addr
209 #undef gethostname
210 #undef gethostbyname
211 #undef getservbyname
212 #undef getpeername
213 #undef shutdown
214 #undef setsockopt
215 #undef listen
216 #undef getsockname
217 #undef accept
218 #undef recvfrom
219 #undef sendto
220
221 #include <iphlpapi.h> /* should be after winsock2.h */
222
223 #include "w32.h"
224 #include <dirent.h>
225 #include "w32common.h"
226 #include "w32heap.h"
227 #include "w32select.h"
228 #include "systime.h"
229 #include "dispextern.h" /* for xstrcasecmp */
230 #include "coding.h" /* for Vlocale_coding_system */
231
232 #include "careadlinkat.h"
233 #include "allocator.h"
234
235 /* For serial_configure and serial_open. */
236 #include "process.h"
237
238 typedef HRESULT (WINAPI * ShGetFolderPath_fn)
239 (IN HWND, IN int, IN HANDLE, IN DWORD, OUT char *);
240
241 Lisp_Object QCloaded_from;
242
243 void globals_of_w32 (void);
244 static DWORD get_rid (PSID);
245 static int is_symlink (const char *);
246 static char * chase_symlinks (const char *);
247 static int enable_privilege (LPCTSTR, BOOL, TOKEN_PRIVILEGES *);
248 static int restore_privilege (TOKEN_PRIVILEGES *);
249 static BOOL WINAPI revert_to_self (void);
250
251 extern int sys_access (const char *, int);
252 extern void *e_malloc (size_t);
253 extern int sys_select (int, SELECT_TYPE *, SELECT_TYPE *, SELECT_TYPE *,
254 struct timespec *, void *);
255 extern int sys_dup (int);
256
257
258
259 \f
260 /* Initialization states.
261
262 WARNING: If you add any more such variables for additional APIs,
263 you MUST add initialization for them to globals_of_w32
264 below. This is because these variables might get set
265 to non-NULL values during dumping, but the dumped Emacs
266 cannot reuse those values, because it could be run on a
267 different version of the OS, where API addresses are
268 different. */
269 static BOOL g_b_init_is_windows_9x;
270 static BOOL g_b_init_open_process_token;
271 static BOOL g_b_init_get_token_information;
272 static BOOL g_b_init_lookup_account_sid;
273 static BOOL g_b_init_get_sid_sub_authority;
274 static BOOL g_b_init_get_sid_sub_authority_count;
275 static BOOL g_b_init_get_security_info;
276 static BOOL g_b_init_get_file_security;
277 static BOOL g_b_init_get_security_descriptor_owner;
278 static BOOL g_b_init_get_security_descriptor_group;
279 static BOOL g_b_init_is_valid_sid;
280 static BOOL g_b_init_create_toolhelp32_snapshot;
281 static BOOL g_b_init_process32_first;
282 static BOOL g_b_init_process32_next;
283 static BOOL g_b_init_open_thread_token;
284 static BOOL g_b_init_impersonate_self;
285 static BOOL g_b_init_revert_to_self;
286 static BOOL g_b_init_get_process_memory_info;
287 static BOOL g_b_init_get_process_working_set_size;
288 static BOOL g_b_init_global_memory_status;
289 static BOOL g_b_init_global_memory_status_ex;
290 static BOOL g_b_init_get_length_sid;
291 static BOOL g_b_init_equal_sid;
292 static BOOL g_b_init_copy_sid;
293 static BOOL g_b_init_get_native_system_info;
294 static BOOL g_b_init_get_system_times;
295 static BOOL g_b_init_create_symbolic_link;
296 static BOOL g_b_init_get_security_descriptor_dacl;
297 static BOOL g_b_init_convert_sd_to_sddl;
298 static BOOL g_b_init_convert_sddl_to_sd;
299 static BOOL g_b_init_is_valid_security_descriptor;
300 static BOOL g_b_init_set_file_security;
301 static BOOL g_b_init_get_adapters_info;
302
303 int w32_unicode_filenames;
304
305 /*
306 BEGIN: Wrapper functions around OpenProcessToken
307 and other functions in advapi32.dll that are only
308 supported in Windows NT / 2k / XP
309 */
310 /* ** Function pointer typedefs ** */
311 typedef BOOL (WINAPI * OpenProcessToken_Proc) (
312 HANDLE ProcessHandle,
313 DWORD DesiredAccess,
314 PHANDLE TokenHandle);
315 typedef BOOL (WINAPI * GetTokenInformation_Proc) (
316 HANDLE TokenHandle,
317 TOKEN_INFORMATION_CLASS TokenInformationClass,
318 LPVOID TokenInformation,
319 DWORD TokenInformationLength,
320 PDWORD ReturnLength);
321 typedef BOOL (WINAPI * GetProcessTimes_Proc) (
322 HANDLE process_handle,
323 LPFILETIME creation_time,
324 LPFILETIME exit_time,
325 LPFILETIME kernel_time,
326 LPFILETIME user_time);
327
328 GetProcessTimes_Proc get_process_times_fn = NULL;
329
330 #ifdef _UNICODE
331 const char * const LookupAccountSid_Name = "LookupAccountSidW";
332 const char * const GetFileSecurity_Name = "GetFileSecurityW";
333 const char * const SetFileSecurity_Name = "SetFileSecurityW";
334 #else
335 const char * const LookupAccountSid_Name = "LookupAccountSidA";
336 const char * const GetFileSecurity_Name = "GetFileSecurityA";
337 const char * const SetFileSecurity_Name = "SetFileSecurityA";
338 #endif
339 typedef BOOL (WINAPI * LookupAccountSid_Proc) (
340 LPCTSTR lpSystemName,
341 PSID Sid,
342 LPTSTR Name,
343 LPDWORD cbName,
344 LPTSTR DomainName,
345 LPDWORD cbDomainName,
346 PSID_NAME_USE peUse);
347 typedef PDWORD (WINAPI * GetSidSubAuthority_Proc) (
348 PSID pSid,
349 DWORD n);
350 typedef PUCHAR (WINAPI * GetSidSubAuthorityCount_Proc) (
351 PSID pSid);
352 typedef DWORD (WINAPI * GetSecurityInfo_Proc) (
353 HANDLE handle,
354 SE_OBJECT_TYPE ObjectType,
355 SECURITY_INFORMATION SecurityInfo,
356 PSID *ppsidOwner,
357 PSID *ppsidGroup,
358 PACL *ppDacl,
359 PACL *ppSacl,
360 PSECURITY_DESCRIPTOR *ppSecurityDescriptor);
361 typedef BOOL (WINAPI * GetFileSecurity_Proc) (
362 LPCTSTR lpFileName,
363 SECURITY_INFORMATION RequestedInformation,
364 PSECURITY_DESCRIPTOR pSecurityDescriptor,
365 DWORD nLength,
366 LPDWORD lpnLengthNeeded);
367 typedef BOOL (WINAPI *SetFileSecurity_Proc) (
368 LPCTSTR lpFileName,
369 SECURITY_INFORMATION SecurityInformation,
370 PSECURITY_DESCRIPTOR pSecurityDescriptor);
371 typedef BOOL (WINAPI * GetSecurityDescriptorOwner_Proc) (
372 PSECURITY_DESCRIPTOR pSecurityDescriptor,
373 PSID *pOwner,
374 LPBOOL lpbOwnerDefaulted);
375 typedef BOOL (WINAPI * GetSecurityDescriptorGroup_Proc) (
376 PSECURITY_DESCRIPTOR pSecurityDescriptor,
377 PSID *pGroup,
378 LPBOOL lpbGroupDefaulted);
379 typedef BOOL (WINAPI *GetSecurityDescriptorDacl_Proc) (
380 PSECURITY_DESCRIPTOR pSecurityDescriptor,
381 LPBOOL lpbDaclPresent,
382 PACL *pDacl,
383 LPBOOL lpbDaclDefaulted);
384 typedef BOOL (WINAPI * IsValidSid_Proc) (
385 PSID sid);
386 typedef HANDLE (WINAPI * CreateToolhelp32Snapshot_Proc) (
387 DWORD dwFlags,
388 DWORD th32ProcessID);
389 typedef BOOL (WINAPI * Process32First_Proc) (
390 HANDLE hSnapshot,
391 LPPROCESSENTRY32 lppe);
392 typedef BOOL (WINAPI * Process32Next_Proc) (
393 HANDLE hSnapshot,
394 LPPROCESSENTRY32 lppe);
395 typedef BOOL (WINAPI * OpenThreadToken_Proc) (
396 HANDLE ThreadHandle,
397 DWORD DesiredAccess,
398 BOOL OpenAsSelf,
399 PHANDLE TokenHandle);
400 typedef BOOL (WINAPI * ImpersonateSelf_Proc) (
401 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel);
402 typedef BOOL (WINAPI * RevertToSelf_Proc) (void);
403 typedef BOOL (WINAPI * GetProcessMemoryInfo_Proc) (
404 HANDLE Process,
405 PPROCESS_MEMORY_COUNTERS ppsmemCounters,
406 DWORD cb);
407 typedef BOOL (WINAPI * GetProcessWorkingSetSize_Proc) (
408 HANDLE hProcess,
409 PSIZE_T lpMinimumWorkingSetSize,
410 PSIZE_T lpMaximumWorkingSetSize);
411 typedef BOOL (WINAPI * GlobalMemoryStatus_Proc) (
412 LPMEMORYSTATUS lpBuffer);
413 typedef BOOL (WINAPI * GlobalMemoryStatusEx_Proc) (
414 LPMEMORY_STATUS_EX lpBuffer);
415 typedef BOOL (WINAPI * CopySid_Proc) (
416 DWORD nDestinationSidLength,
417 PSID pDestinationSid,
418 PSID pSourceSid);
419 typedef BOOL (WINAPI * EqualSid_Proc) (
420 PSID pSid1,
421 PSID pSid2);
422 typedef DWORD (WINAPI * GetLengthSid_Proc) (
423 PSID pSid);
424 typedef void (WINAPI * GetNativeSystemInfo_Proc) (
425 LPSYSTEM_INFO lpSystemInfo);
426 typedef BOOL (WINAPI * GetSystemTimes_Proc) (
427 LPFILETIME lpIdleTime,
428 LPFILETIME lpKernelTime,
429 LPFILETIME lpUserTime);
430 typedef BOOLEAN (WINAPI *CreateSymbolicLink_Proc) (
431 LPTSTR lpSymlinkFileName,
432 LPTSTR lpTargetFileName,
433 DWORD dwFlags);
434 typedef BOOL (WINAPI *ConvertStringSecurityDescriptorToSecurityDescriptor_Proc) (
435 LPCTSTR StringSecurityDescriptor,
436 DWORD StringSDRevision,
437 PSECURITY_DESCRIPTOR *SecurityDescriptor,
438 PULONG SecurityDescriptorSize);
439 typedef BOOL (WINAPI *ConvertSecurityDescriptorToStringSecurityDescriptor_Proc) (
440 PSECURITY_DESCRIPTOR SecurityDescriptor,
441 DWORD RequestedStringSDRevision,
442 SECURITY_INFORMATION SecurityInformation,
443 LPTSTR *StringSecurityDescriptor,
444 PULONG StringSecurityDescriptorLen);
445 typedef BOOL (WINAPI *IsValidSecurityDescriptor_Proc) (PSECURITY_DESCRIPTOR);
446 typedef DWORD (WINAPI *GetAdaptersInfo_Proc) (
447 PIP_ADAPTER_INFO pAdapterInfo,
448 PULONG pOutBufLen);
449
450 /* ** A utility function ** */
451 static BOOL
452 is_windows_9x (void)
453 {
454 static BOOL s_b_ret = 0;
455 OSVERSIONINFO os_ver;
456 if (g_b_init_is_windows_9x == 0)
457 {
458 g_b_init_is_windows_9x = 1;
459 ZeroMemory (&os_ver, sizeof (OSVERSIONINFO));
460 os_ver.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
461 if (GetVersionEx (&os_ver))
462 {
463 s_b_ret = (os_ver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
464 }
465 }
466 return s_b_ret;
467 }
468
469 static Lisp_Object ltime (ULONGLONG);
470
471 /* Get total user and system times for get-internal-run-time.
472 Returns a list of integers if the times are provided by the OS
473 (NT derivatives), otherwise it returns the result of current-time. */
474 Lisp_Object
475 w32_get_internal_run_time (void)
476 {
477 if (get_process_times_fn)
478 {
479 FILETIME create, exit, kernel, user;
480 HANDLE proc = GetCurrentProcess ();
481 if ((*get_process_times_fn) (proc, &create, &exit, &kernel, &user))
482 {
483 LARGE_INTEGER user_int, kernel_int, total;
484 user_int.LowPart = user.dwLowDateTime;
485 user_int.HighPart = user.dwHighDateTime;
486 kernel_int.LowPart = kernel.dwLowDateTime;
487 kernel_int.HighPart = kernel.dwHighDateTime;
488 total.QuadPart = user_int.QuadPart + kernel_int.QuadPart;
489 return ltime (total.QuadPart);
490 }
491 }
492
493 return Fcurrent_time ();
494 }
495
496 /* ** The wrapper functions ** */
497
498 static BOOL WINAPI
499 open_process_token (HANDLE ProcessHandle,
500 DWORD DesiredAccess,
501 PHANDLE TokenHandle)
502 {
503 static OpenProcessToken_Proc s_pfn_Open_Process_Token = NULL;
504 HMODULE hm_advapi32 = NULL;
505 if (is_windows_9x () == TRUE)
506 {
507 return FALSE;
508 }
509 if (g_b_init_open_process_token == 0)
510 {
511 g_b_init_open_process_token = 1;
512 hm_advapi32 = LoadLibrary ("Advapi32.dll");
513 s_pfn_Open_Process_Token =
514 (OpenProcessToken_Proc) GetProcAddress (hm_advapi32, "OpenProcessToken");
515 }
516 if (s_pfn_Open_Process_Token == NULL)
517 {
518 return FALSE;
519 }
520 return (
521 s_pfn_Open_Process_Token (
522 ProcessHandle,
523 DesiredAccess,
524 TokenHandle)
525 );
526 }
527
528 static BOOL WINAPI
529 get_token_information (HANDLE TokenHandle,
530 TOKEN_INFORMATION_CLASS TokenInformationClass,
531 LPVOID TokenInformation,
532 DWORD TokenInformationLength,
533 PDWORD ReturnLength)
534 {
535 static GetTokenInformation_Proc s_pfn_Get_Token_Information = NULL;
536 HMODULE hm_advapi32 = NULL;
537 if (is_windows_9x () == TRUE)
538 {
539 return FALSE;
540 }
541 if (g_b_init_get_token_information == 0)
542 {
543 g_b_init_get_token_information = 1;
544 hm_advapi32 = LoadLibrary ("Advapi32.dll");
545 s_pfn_Get_Token_Information =
546 (GetTokenInformation_Proc) GetProcAddress (hm_advapi32, "GetTokenInformation");
547 }
548 if (s_pfn_Get_Token_Information == NULL)
549 {
550 return FALSE;
551 }
552 return (
553 s_pfn_Get_Token_Information (
554 TokenHandle,
555 TokenInformationClass,
556 TokenInformation,
557 TokenInformationLength,
558 ReturnLength)
559 );
560 }
561
562 static BOOL WINAPI
563 lookup_account_sid (LPCTSTR lpSystemName,
564 PSID Sid,
565 LPTSTR Name,
566 LPDWORD cbName,
567 LPTSTR DomainName,
568 LPDWORD cbDomainName,
569 PSID_NAME_USE peUse)
570 {
571 static LookupAccountSid_Proc s_pfn_Lookup_Account_Sid = NULL;
572 HMODULE hm_advapi32 = NULL;
573 if (is_windows_9x () == TRUE)
574 {
575 return FALSE;
576 }
577 if (g_b_init_lookup_account_sid == 0)
578 {
579 g_b_init_lookup_account_sid = 1;
580 hm_advapi32 = LoadLibrary ("Advapi32.dll");
581 s_pfn_Lookup_Account_Sid =
582 (LookupAccountSid_Proc) GetProcAddress (hm_advapi32, LookupAccountSid_Name);
583 }
584 if (s_pfn_Lookup_Account_Sid == NULL)
585 {
586 return FALSE;
587 }
588 return (
589 s_pfn_Lookup_Account_Sid (
590 lpSystemName,
591 Sid,
592 Name,
593 cbName,
594 DomainName,
595 cbDomainName,
596 peUse)
597 );
598 }
599
600 static PDWORD WINAPI
601 get_sid_sub_authority (PSID pSid, DWORD n)
602 {
603 static GetSidSubAuthority_Proc s_pfn_Get_Sid_Sub_Authority = NULL;
604 static DWORD zero = 0U;
605 HMODULE hm_advapi32 = NULL;
606 if (is_windows_9x () == TRUE)
607 {
608 return &zero;
609 }
610 if (g_b_init_get_sid_sub_authority == 0)
611 {
612 g_b_init_get_sid_sub_authority = 1;
613 hm_advapi32 = LoadLibrary ("Advapi32.dll");
614 s_pfn_Get_Sid_Sub_Authority =
615 (GetSidSubAuthority_Proc) GetProcAddress (
616 hm_advapi32, "GetSidSubAuthority");
617 }
618 if (s_pfn_Get_Sid_Sub_Authority == NULL)
619 {
620 return &zero;
621 }
622 return (s_pfn_Get_Sid_Sub_Authority (pSid, n));
623 }
624
625 static PUCHAR WINAPI
626 get_sid_sub_authority_count (PSID pSid)
627 {
628 static GetSidSubAuthorityCount_Proc s_pfn_Get_Sid_Sub_Authority_Count = NULL;
629 static UCHAR zero = 0U;
630 HMODULE hm_advapi32 = NULL;
631 if (is_windows_9x () == TRUE)
632 {
633 return &zero;
634 }
635 if (g_b_init_get_sid_sub_authority_count == 0)
636 {
637 g_b_init_get_sid_sub_authority_count = 1;
638 hm_advapi32 = LoadLibrary ("Advapi32.dll");
639 s_pfn_Get_Sid_Sub_Authority_Count =
640 (GetSidSubAuthorityCount_Proc) GetProcAddress (
641 hm_advapi32, "GetSidSubAuthorityCount");
642 }
643 if (s_pfn_Get_Sid_Sub_Authority_Count == NULL)
644 {
645 return &zero;
646 }
647 return (s_pfn_Get_Sid_Sub_Authority_Count (pSid));
648 }
649
650 static DWORD WINAPI
651 get_security_info (HANDLE handle,
652 SE_OBJECT_TYPE ObjectType,
653 SECURITY_INFORMATION SecurityInfo,
654 PSID *ppsidOwner,
655 PSID *ppsidGroup,
656 PACL *ppDacl,
657 PACL *ppSacl,
658 PSECURITY_DESCRIPTOR *ppSecurityDescriptor)
659 {
660 static GetSecurityInfo_Proc s_pfn_Get_Security_Info = NULL;
661 HMODULE hm_advapi32 = NULL;
662 if (is_windows_9x () == TRUE)
663 {
664 return FALSE;
665 }
666 if (g_b_init_get_security_info == 0)
667 {
668 g_b_init_get_security_info = 1;
669 hm_advapi32 = LoadLibrary ("Advapi32.dll");
670 s_pfn_Get_Security_Info =
671 (GetSecurityInfo_Proc) GetProcAddress (
672 hm_advapi32, "GetSecurityInfo");
673 }
674 if (s_pfn_Get_Security_Info == NULL)
675 {
676 return FALSE;
677 }
678 return (s_pfn_Get_Security_Info (handle, ObjectType, SecurityInfo,
679 ppsidOwner, ppsidGroup, ppDacl, ppSacl,
680 ppSecurityDescriptor));
681 }
682
683 static BOOL WINAPI
684 get_file_security (LPCTSTR lpFileName,
685 SECURITY_INFORMATION RequestedInformation,
686 PSECURITY_DESCRIPTOR pSecurityDescriptor,
687 DWORD nLength,
688 LPDWORD lpnLengthNeeded)
689 {
690 static GetFileSecurity_Proc s_pfn_Get_File_Security = NULL;
691 HMODULE hm_advapi32 = NULL;
692 if (is_windows_9x () == TRUE)
693 {
694 errno = ENOTSUP;
695 return FALSE;
696 }
697 if (g_b_init_get_file_security == 0)
698 {
699 g_b_init_get_file_security = 1;
700 hm_advapi32 = LoadLibrary ("Advapi32.dll");
701 s_pfn_Get_File_Security =
702 (GetFileSecurity_Proc) GetProcAddress (
703 hm_advapi32, GetFileSecurity_Name);
704 }
705 if (s_pfn_Get_File_Security == NULL)
706 {
707 errno = ENOTSUP;
708 return FALSE;
709 }
710 return (s_pfn_Get_File_Security (lpFileName, RequestedInformation,
711 pSecurityDescriptor, nLength,
712 lpnLengthNeeded));
713 }
714
715 static BOOL WINAPI
716 set_file_security (LPCTSTR lpFileName,
717 SECURITY_INFORMATION SecurityInformation,
718 PSECURITY_DESCRIPTOR pSecurityDescriptor)
719 {
720 static SetFileSecurity_Proc s_pfn_Set_File_Security = NULL;
721 HMODULE hm_advapi32 = NULL;
722 if (is_windows_9x () == TRUE)
723 {
724 errno = ENOTSUP;
725 return FALSE;
726 }
727 if (g_b_init_set_file_security == 0)
728 {
729 g_b_init_set_file_security = 1;
730 hm_advapi32 = LoadLibrary ("Advapi32.dll");
731 s_pfn_Set_File_Security =
732 (SetFileSecurity_Proc) GetProcAddress (
733 hm_advapi32, SetFileSecurity_Name);
734 }
735 if (s_pfn_Set_File_Security == NULL)
736 {
737 errno = ENOTSUP;
738 return FALSE;
739 }
740 return (s_pfn_Set_File_Security (lpFileName, SecurityInformation,
741 pSecurityDescriptor));
742 }
743
744 static BOOL WINAPI
745 get_security_descriptor_owner (PSECURITY_DESCRIPTOR pSecurityDescriptor,
746 PSID *pOwner,
747 LPBOOL lpbOwnerDefaulted)
748 {
749 static GetSecurityDescriptorOwner_Proc s_pfn_Get_Security_Descriptor_Owner = NULL;
750 HMODULE hm_advapi32 = NULL;
751 if (is_windows_9x () == TRUE)
752 {
753 errno = ENOTSUP;
754 return FALSE;
755 }
756 if (g_b_init_get_security_descriptor_owner == 0)
757 {
758 g_b_init_get_security_descriptor_owner = 1;
759 hm_advapi32 = LoadLibrary ("Advapi32.dll");
760 s_pfn_Get_Security_Descriptor_Owner =
761 (GetSecurityDescriptorOwner_Proc) GetProcAddress (
762 hm_advapi32, "GetSecurityDescriptorOwner");
763 }
764 if (s_pfn_Get_Security_Descriptor_Owner == NULL)
765 {
766 errno = ENOTSUP;
767 return FALSE;
768 }
769 return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor, pOwner,
770 lpbOwnerDefaulted));
771 }
772
773 static BOOL WINAPI
774 get_security_descriptor_group (PSECURITY_DESCRIPTOR pSecurityDescriptor,
775 PSID *pGroup,
776 LPBOOL lpbGroupDefaulted)
777 {
778 static GetSecurityDescriptorGroup_Proc s_pfn_Get_Security_Descriptor_Group = NULL;
779 HMODULE hm_advapi32 = NULL;
780 if (is_windows_9x () == TRUE)
781 {
782 errno = ENOTSUP;
783 return FALSE;
784 }
785 if (g_b_init_get_security_descriptor_group == 0)
786 {
787 g_b_init_get_security_descriptor_group = 1;
788 hm_advapi32 = LoadLibrary ("Advapi32.dll");
789 s_pfn_Get_Security_Descriptor_Group =
790 (GetSecurityDescriptorGroup_Proc) GetProcAddress (
791 hm_advapi32, "GetSecurityDescriptorGroup");
792 }
793 if (s_pfn_Get_Security_Descriptor_Group == NULL)
794 {
795 errno = ENOTSUP;
796 return FALSE;
797 }
798 return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor, pGroup,
799 lpbGroupDefaulted));
800 }
801
802 static BOOL WINAPI
803 get_security_descriptor_dacl (PSECURITY_DESCRIPTOR pSecurityDescriptor,
804 LPBOOL lpbDaclPresent,
805 PACL *pDacl,
806 LPBOOL lpbDaclDefaulted)
807 {
808 static GetSecurityDescriptorDacl_Proc s_pfn_Get_Security_Descriptor_Dacl = NULL;
809 HMODULE hm_advapi32 = NULL;
810 if (is_windows_9x () == TRUE)
811 {
812 errno = ENOTSUP;
813 return FALSE;
814 }
815 if (g_b_init_get_security_descriptor_dacl == 0)
816 {
817 g_b_init_get_security_descriptor_dacl = 1;
818 hm_advapi32 = LoadLibrary ("Advapi32.dll");
819 s_pfn_Get_Security_Descriptor_Dacl =
820 (GetSecurityDescriptorDacl_Proc) GetProcAddress (
821 hm_advapi32, "GetSecurityDescriptorDacl");
822 }
823 if (s_pfn_Get_Security_Descriptor_Dacl == NULL)
824 {
825 errno = ENOTSUP;
826 return FALSE;
827 }
828 return (s_pfn_Get_Security_Descriptor_Dacl (pSecurityDescriptor,
829 lpbDaclPresent, pDacl,
830 lpbDaclDefaulted));
831 }
832
833 static BOOL WINAPI
834 is_valid_sid (PSID sid)
835 {
836 static IsValidSid_Proc s_pfn_Is_Valid_Sid = NULL;
837 HMODULE hm_advapi32 = NULL;
838 if (is_windows_9x () == TRUE)
839 {
840 return FALSE;
841 }
842 if (g_b_init_is_valid_sid == 0)
843 {
844 g_b_init_is_valid_sid = 1;
845 hm_advapi32 = LoadLibrary ("Advapi32.dll");
846 s_pfn_Is_Valid_Sid =
847 (IsValidSid_Proc) GetProcAddress (
848 hm_advapi32, "IsValidSid");
849 }
850 if (s_pfn_Is_Valid_Sid == NULL)
851 {
852 return FALSE;
853 }
854 return (s_pfn_Is_Valid_Sid (sid));
855 }
856
857 static BOOL WINAPI
858 equal_sid (PSID sid1, PSID sid2)
859 {
860 static EqualSid_Proc s_pfn_Equal_Sid = NULL;
861 HMODULE hm_advapi32 = NULL;
862 if (is_windows_9x () == TRUE)
863 {
864 return FALSE;
865 }
866 if (g_b_init_equal_sid == 0)
867 {
868 g_b_init_equal_sid = 1;
869 hm_advapi32 = LoadLibrary ("Advapi32.dll");
870 s_pfn_Equal_Sid =
871 (EqualSid_Proc) GetProcAddress (
872 hm_advapi32, "EqualSid");
873 }
874 if (s_pfn_Equal_Sid == NULL)
875 {
876 return FALSE;
877 }
878 return (s_pfn_Equal_Sid (sid1, sid2));
879 }
880
881 static DWORD WINAPI
882 get_length_sid (PSID sid)
883 {
884 static GetLengthSid_Proc s_pfn_Get_Length_Sid = NULL;
885 HMODULE hm_advapi32 = NULL;
886 if (is_windows_9x () == TRUE)
887 {
888 return 0;
889 }
890 if (g_b_init_get_length_sid == 0)
891 {
892 g_b_init_get_length_sid = 1;
893 hm_advapi32 = LoadLibrary ("Advapi32.dll");
894 s_pfn_Get_Length_Sid =
895 (GetLengthSid_Proc) GetProcAddress (
896 hm_advapi32, "GetLengthSid");
897 }
898 if (s_pfn_Get_Length_Sid == NULL)
899 {
900 return 0;
901 }
902 return (s_pfn_Get_Length_Sid (sid));
903 }
904
905 static BOOL WINAPI
906 copy_sid (DWORD destlen, PSID dest, PSID src)
907 {
908 static CopySid_Proc s_pfn_Copy_Sid = NULL;
909 HMODULE hm_advapi32 = NULL;
910 if (is_windows_9x () == TRUE)
911 {
912 return FALSE;
913 }
914 if (g_b_init_copy_sid == 0)
915 {
916 g_b_init_copy_sid = 1;
917 hm_advapi32 = LoadLibrary ("Advapi32.dll");
918 s_pfn_Copy_Sid =
919 (CopySid_Proc) GetProcAddress (
920 hm_advapi32, "CopySid");
921 }
922 if (s_pfn_Copy_Sid == NULL)
923 {
924 return FALSE;
925 }
926 return (s_pfn_Copy_Sid (destlen, dest, src));
927 }
928
929 /*
930 END: Wrapper functions around OpenProcessToken
931 and other functions in advapi32.dll that are only
932 supported in Windows NT / 2k / XP
933 */
934
935 static void WINAPI
936 get_native_system_info (LPSYSTEM_INFO lpSystemInfo)
937 {
938 static GetNativeSystemInfo_Proc s_pfn_Get_Native_System_Info = NULL;
939 if (is_windows_9x () != TRUE)
940 {
941 if (g_b_init_get_native_system_info == 0)
942 {
943 g_b_init_get_native_system_info = 1;
944 s_pfn_Get_Native_System_Info =
945 (GetNativeSystemInfo_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
946 "GetNativeSystemInfo");
947 }
948 if (s_pfn_Get_Native_System_Info != NULL)
949 s_pfn_Get_Native_System_Info (lpSystemInfo);
950 }
951 else
952 lpSystemInfo->dwNumberOfProcessors = -1;
953 }
954
955 static BOOL WINAPI
956 get_system_times (LPFILETIME lpIdleTime,
957 LPFILETIME lpKernelTime,
958 LPFILETIME lpUserTime)
959 {
960 static GetSystemTimes_Proc s_pfn_Get_System_times = NULL;
961 if (is_windows_9x () == TRUE)
962 {
963 return FALSE;
964 }
965 if (g_b_init_get_system_times == 0)
966 {
967 g_b_init_get_system_times = 1;
968 s_pfn_Get_System_times =
969 (GetSystemTimes_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
970 "GetSystemTimes");
971 }
972 if (s_pfn_Get_System_times == NULL)
973 return FALSE;
974 return (s_pfn_Get_System_times (lpIdleTime, lpKernelTime, lpUserTime));
975 }
976
977 static BOOLEAN WINAPI
978 create_symbolic_link (LPTSTR lpSymlinkFilename,
979 LPTSTR lpTargetFileName,
980 DWORD dwFlags)
981 {
982 static CreateSymbolicLink_Proc s_pfn_Create_Symbolic_Link = NULL;
983 BOOLEAN retval;
984
985 if (is_windows_9x () == TRUE)
986 {
987 errno = ENOSYS;
988 return 0;
989 }
990 if (g_b_init_create_symbolic_link == 0)
991 {
992 g_b_init_create_symbolic_link = 1;
993 #ifdef _UNICODE
994 s_pfn_Create_Symbolic_Link =
995 (CreateSymbolicLink_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
996 "CreateSymbolicLinkW");
997 #else
998 s_pfn_Create_Symbolic_Link =
999 (CreateSymbolicLink_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
1000 "CreateSymbolicLinkA");
1001 #endif
1002 }
1003 if (s_pfn_Create_Symbolic_Link == NULL)
1004 {
1005 errno = ENOSYS;
1006 return 0;
1007 }
1008
1009 retval = s_pfn_Create_Symbolic_Link (lpSymlinkFilename, lpTargetFileName,
1010 dwFlags);
1011 /* If we were denied creation of the symlink, try again after
1012 enabling the SeCreateSymbolicLinkPrivilege for our process. */
1013 if (!retval)
1014 {
1015 TOKEN_PRIVILEGES priv_current;
1016
1017 if (enable_privilege (SE_CREATE_SYMBOLIC_LINK_NAME, TRUE, &priv_current))
1018 {
1019 retval = s_pfn_Create_Symbolic_Link (lpSymlinkFilename, lpTargetFileName,
1020 dwFlags);
1021 restore_privilege (&priv_current);
1022 revert_to_self ();
1023 }
1024 }
1025 return retval;
1026 }
1027
1028 static BOOL WINAPI
1029 is_valid_security_descriptor (PSECURITY_DESCRIPTOR pSecurityDescriptor)
1030 {
1031 static IsValidSecurityDescriptor_Proc s_pfn_Is_Valid_Security_Descriptor_Proc = NULL;
1032
1033 if (is_windows_9x () == TRUE)
1034 {
1035 errno = ENOTSUP;
1036 return FALSE;
1037 }
1038
1039 if (g_b_init_is_valid_security_descriptor == 0)
1040 {
1041 g_b_init_is_valid_security_descriptor = 1;
1042 s_pfn_Is_Valid_Security_Descriptor_Proc =
1043 (IsValidSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1044 "IsValidSecurityDescriptor");
1045 }
1046 if (s_pfn_Is_Valid_Security_Descriptor_Proc == NULL)
1047 {
1048 errno = ENOTSUP;
1049 return FALSE;
1050 }
1051
1052 return s_pfn_Is_Valid_Security_Descriptor_Proc (pSecurityDescriptor);
1053 }
1054
1055 static BOOL WINAPI
1056 convert_sd_to_sddl (PSECURITY_DESCRIPTOR SecurityDescriptor,
1057 DWORD RequestedStringSDRevision,
1058 SECURITY_INFORMATION SecurityInformation,
1059 LPTSTR *StringSecurityDescriptor,
1060 PULONG StringSecurityDescriptorLen)
1061 {
1062 static ConvertSecurityDescriptorToStringSecurityDescriptor_Proc s_pfn_Convert_SD_To_SDDL = NULL;
1063 BOOL retval;
1064
1065 if (is_windows_9x () == TRUE)
1066 {
1067 errno = ENOTSUP;
1068 return FALSE;
1069 }
1070
1071 if (g_b_init_convert_sd_to_sddl == 0)
1072 {
1073 g_b_init_convert_sd_to_sddl = 1;
1074 #ifdef _UNICODE
1075 s_pfn_Convert_SD_To_SDDL =
1076 (ConvertSecurityDescriptorToStringSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1077 "ConvertSecurityDescriptorToStringSecurityDescriptorW");
1078 #else
1079 s_pfn_Convert_SD_To_SDDL =
1080 (ConvertSecurityDescriptorToStringSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1081 "ConvertSecurityDescriptorToStringSecurityDescriptorA");
1082 #endif
1083 }
1084 if (s_pfn_Convert_SD_To_SDDL == NULL)
1085 {
1086 errno = ENOTSUP;
1087 return FALSE;
1088 }
1089
1090 retval = s_pfn_Convert_SD_To_SDDL (SecurityDescriptor,
1091 RequestedStringSDRevision,
1092 SecurityInformation,
1093 StringSecurityDescriptor,
1094 StringSecurityDescriptorLen);
1095
1096 return retval;
1097 }
1098
1099 static BOOL WINAPI
1100 convert_sddl_to_sd (LPCTSTR StringSecurityDescriptor,
1101 DWORD StringSDRevision,
1102 PSECURITY_DESCRIPTOR *SecurityDescriptor,
1103 PULONG SecurityDescriptorSize)
1104 {
1105 static ConvertStringSecurityDescriptorToSecurityDescriptor_Proc s_pfn_Convert_SDDL_To_SD = NULL;
1106 BOOL retval;
1107
1108 if (is_windows_9x () == TRUE)
1109 {
1110 errno = ENOTSUP;
1111 return FALSE;
1112 }
1113
1114 if (g_b_init_convert_sddl_to_sd == 0)
1115 {
1116 g_b_init_convert_sddl_to_sd = 1;
1117 #ifdef _UNICODE
1118 s_pfn_Convert_SDDL_To_SD =
1119 (ConvertStringSecurityDescriptorToSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1120 "ConvertStringSecurityDescriptorToSecurityDescriptorW");
1121 #else
1122 s_pfn_Convert_SDDL_To_SD =
1123 (ConvertStringSecurityDescriptorToSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"),
1124 "ConvertStringSecurityDescriptorToSecurityDescriptorA");
1125 #endif
1126 }
1127 if (s_pfn_Convert_SDDL_To_SD == NULL)
1128 {
1129 errno = ENOTSUP;
1130 return FALSE;
1131 }
1132
1133 retval = s_pfn_Convert_SDDL_To_SD (StringSecurityDescriptor,
1134 StringSDRevision,
1135 SecurityDescriptor,
1136 SecurityDescriptorSize);
1137
1138 return retval;
1139 }
1140
1141 static DWORD WINAPI
1142 get_adapters_info (PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen)
1143 {
1144 static GetAdaptersInfo_Proc s_pfn_Get_Adapters_Info = NULL;
1145 HMODULE hm_iphlpapi = NULL;
1146
1147 if (is_windows_9x () == TRUE)
1148 return ERROR_NOT_SUPPORTED;
1149
1150 if (g_b_init_get_adapters_info == 0)
1151 {
1152 g_b_init_get_adapters_info = 1;
1153 hm_iphlpapi = LoadLibrary ("Iphlpapi.dll");
1154 if (hm_iphlpapi)
1155 s_pfn_Get_Adapters_Info = (GetAdaptersInfo_Proc)
1156 GetProcAddress (hm_iphlpapi, "GetAdaptersInfo");
1157 }
1158 if (s_pfn_Get_Adapters_Info == NULL)
1159 return ERROR_NOT_SUPPORTED;
1160 return s_pfn_Get_Adapters_Info (pAdapterInfo, pOutBufLen);
1161 }
1162
1163 \f
1164
1165 /* Return 1 if P is a valid pointer to an object of size SIZE. Return
1166 0 if P is NOT a valid pointer. Return -1 if we cannot validate P.
1167
1168 This is called from alloc.c:valid_pointer_p. */
1169 int
1170 w32_valid_pointer_p (void *p, int size)
1171 {
1172 SIZE_T done;
1173 HANDLE h = OpenProcess (PROCESS_VM_READ, FALSE, GetCurrentProcessId ());
1174
1175 if (h)
1176 {
1177 unsigned char *buf = alloca (size);
1178 int retval = ReadProcessMemory (h, p, buf, size, &done);
1179
1180 CloseHandle (h);
1181 return retval;
1182 }
1183 else
1184 return -1;
1185 }
1186
1187 \f
1188
1189 /* Converting file names from UTF-8 to either UTF-16 or the system
1190 ANSI codepage. */
1191 static int
1192 filename_to_utf16 (const char *fn_in, wchar_t *fn_out)
1193 {
1194 int result = MultiByteToWideChar (CP_UTF8, 0, fn_in, -1, fn_out, MAX_PATH);
1195
1196 if (!result)
1197 {
1198 DWORD err = GetLastError ();
1199
1200 switch (err)
1201 {
1202 case ERROR_INVALID_FLAGS:
1203 case ERROR_INVALID_PARAMETER:
1204 errno = EINVAL;
1205 break;
1206 case ERROR_INSUFFICIENT_BUFFER:
1207 case ERROR_NO_UNICODE_TRANSLATION:
1208 default:
1209 errno = ENOENT;
1210 break;
1211 }
1212 return -1;
1213 }
1214 return 0;
1215 }
1216
1217 static int
1218 filename_from_utf16 (const wchar_t *fn_in, char *fn_out)
1219 {
1220 return -1;
1221 }
1222
1223 static int
1224 filename_to_ansi (const char *fn_in, char *fn_out)
1225 {
1226 wchar_t fn_utf16[MAXPATHLEN];
1227
1228 if (filename_to_utf16 (fn_in, fn_utf16) == 0)
1229 {
1230 int result = WideCharToMultiByte (CP_ACP, 0, fn_utf16, -1,
1231 fn_out, MAX_UTF8_PATH, NULL, NULL);
1232
1233 if (!result)
1234 {
1235 DWORD err = GetLastError ();
1236
1237 switch (err)
1238 {
1239 case ERROR_INVALID_FLAGS:
1240 case ERROR_INVALID_PARAMETER:
1241 errno = EINVAL;
1242 break;
1243 case ERROR_INSUFFICIENT_BUFFER:
1244 case ERROR_NO_UNICODE_TRANSLATION:
1245 default:
1246 errno = ENOENT;
1247 break;
1248 }
1249 return -1;
1250 }
1251 return 0;
1252 }
1253 }
1254
1255 static int
1256 filename_from_ansi (const char *fn_in, char *fn_out)
1257 {
1258 return -1;
1259 }
1260
1261 \f
1262
1263 static char startup_dir[MAX_UTF8_PATH];
1264
1265 /* Get the current working directory. */
1266 char *
1267 getcwd (char *dir, int dirsize)
1268 {
1269 if (!dirsize)
1270 {
1271 errno = EINVAL;
1272 return NULL;
1273 }
1274 if (dirsize <= strlen (startup_dir))
1275 {
1276 errno = ERANGE;
1277 return NULL;
1278 }
1279 #if 0
1280 if (GetCurrentDirectory (MAXPATHLEN, dir) > 0)
1281 return dir;
1282 return NULL;
1283 #else
1284 /* Emacs doesn't actually change directory itself, it stays in the
1285 same directory where it was started. */
1286 strcpy (dir, startup_dir);
1287 return dir;
1288 #endif
1289 }
1290
1291 /* Emulate getloadavg. */
1292
1293 struct load_sample {
1294 time_t sample_time;
1295 ULONGLONG idle;
1296 ULONGLONG kernel;
1297 ULONGLONG user;
1298 };
1299
1300 /* Number of processors on this machine. */
1301 static unsigned num_of_processors;
1302
1303 /* We maintain 1-sec samples for the last 16 minutes in a circular buffer. */
1304 static struct load_sample samples[16*60];
1305 static int first_idx = -1, last_idx = -1;
1306 static int max_idx = sizeof (samples) / sizeof (samples[0]);
1307
1308 static int
1309 buf_next (int from)
1310 {
1311 int next_idx = from + 1;
1312
1313 if (next_idx >= max_idx)
1314 next_idx = 0;
1315
1316 return next_idx;
1317 }
1318
1319 static int
1320 buf_prev (int from)
1321 {
1322 int prev_idx = from - 1;
1323
1324 if (prev_idx < 0)
1325 prev_idx = max_idx - 1;
1326
1327 return prev_idx;
1328 }
1329
1330 static void
1331 sample_system_load (ULONGLONG *idle, ULONGLONG *kernel, ULONGLONG *user)
1332 {
1333 SYSTEM_INFO sysinfo;
1334 FILETIME ft_idle, ft_user, ft_kernel;
1335
1336 /* Initialize the number of processors on this machine. */
1337 if (num_of_processors <= 0)
1338 {
1339 get_native_system_info (&sysinfo);
1340 num_of_processors = sysinfo.dwNumberOfProcessors;
1341 if (num_of_processors <= 0)
1342 {
1343 GetSystemInfo (&sysinfo);
1344 num_of_processors = sysinfo.dwNumberOfProcessors;
1345 }
1346 if (num_of_processors <= 0)
1347 num_of_processors = 1;
1348 }
1349
1350 /* TODO: Take into account threads that are ready to run, by
1351 sampling the "\System\Processor Queue Length" performance
1352 counter. The code below accounts only for threads that are
1353 actually running. */
1354
1355 if (get_system_times (&ft_idle, &ft_kernel, &ft_user))
1356 {
1357 ULARGE_INTEGER uidle, ukernel, uuser;
1358
1359 memcpy (&uidle, &ft_idle, sizeof (ft_idle));
1360 memcpy (&ukernel, &ft_kernel, sizeof (ft_kernel));
1361 memcpy (&uuser, &ft_user, sizeof (ft_user));
1362 *idle = uidle.QuadPart;
1363 *kernel = ukernel.QuadPart;
1364 *user = uuser.QuadPart;
1365 }
1366 else
1367 {
1368 *idle = 0;
1369 *kernel = 0;
1370 *user = 0;
1371 }
1372 }
1373
1374 /* Produce the load average for a given time interval, using the
1375 samples in the samples[] array. WHICH can be 0, 1, or 2, meaning
1376 1-minute, 5-minute, or 15-minute average, respectively. */
1377 static double
1378 getavg (int which)
1379 {
1380 double retval = -1.0;
1381 double tdiff;
1382 int idx;
1383 double span = (which == 0 ? 1.0 : (which == 1 ? 5.0 : 15.0)) * 60;
1384 time_t now = samples[last_idx].sample_time;
1385
1386 if (first_idx != last_idx)
1387 {
1388 for (idx = buf_prev (last_idx); ; idx = buf_prev (idx))
1389 {
1390 tdiff = difftime (now, samples[idx].sample_time);
1391 if (tdiff >= span - 2*DBL_EPSILON*now)
1392 {
1393 long double sys =
1394 samples[last_idx].kernel + samples[last_idx].user
1395 - (samples[idx].kernel + samples[idx].user);
1396 long double idl = samples[last_idx].idle - samples[idx].idle;
1397
1398 retval = (1.0 - idl / sys) * num_of_processors;
1399 break;
1400 }
1401 if (idx == first_idx)
1402 break;
1403 }
1404 }
1405
1406 return retval;
1407 }
1408
1409 int
1410 getloadavg (double loadavg[], int nelem)
1411 {
1412 int elem;
1413 ULONGLONG idle, kernel, user;
1414 time_t now = time (NULL);
1415
1416 /* Store another sample. We ignore samples that are less than 1 sec
1417 apart. */
1418 if (difftime (now, samples[last_idx].sample_time) >= 1.0 - 2*DBL_EPSILON*now)
1419 {
1420 sample_system_load (&idle, &kernel, &user);
1421 last_idx = buf_next (last_idx);
1422 samples[last_idx].sample_time = now;
1423 samples[last_idx].idle = idle;
1424 samples[last_idx].kernel = kernel;
1425 samples[last_idx].user = user;
1426 /* If the buffer has more that 15 min worth of samples, discard
1427 the old ones. */
1428 if (first_idx == -1)
1429 first_idx = last_idx;
1430 while (first_idx != last_idx
1431 && (difftime (now, samples[first_idx].sample_time)
1432 >= 15.0*60 + 2*DBL_EPSILON*now))
1433 first_idx = buf_next (first_idx);
1434 }
1435
1436 for (elem = 0; elem < nelem; elem++)
1437 {
1438 double avg = getavg (elem);
1439
1440 if (avg < 0)
1441 break;
1442 loadavg[elem] = avg;
1443 }
1444
1445 return elem;
1446 }
1447
1448 /* Emulate getpwuid, getpwnam and others. */
1449
1450 #define PASSWD_FIELD_SIZE 256
1451
1452 static char dflt_passwd_name[PASSWD_FIELD_SIZE];
1453 static char dflt_passwd_passwd[PASSWD_FIELD_SIZE];
1454 static char dflt_passwd_gecos[PASSWD_FIELD_SIZE];
1455 static char dflt_passwd_dir[PASSWD_FIELD_SIZE];
1456 static char dflt_passwd_shell[PASSWD_FIELD_SIZE];
1457
1458 static struct passwd dflt_passwd =
1459 {
1460 dflt_passwd_name,
1461 dflt_passwd_passwd,
1462 0,
1463 0,
1464 0,
1465 dflt_passwd_gecos,
1466 dflt_passwd_dir,
1467 dflt_passwd_shell,
1468 };
1469
1470 static char dflt_group_name[GNLEN+1];
1471
1472 static struct group dflt_group =
1473 {
1474 /* When group information is not available, we return this as the
1475 group for all files. */
1476 dflt_group_name,
1477 0,
1478 };
1479
1480 unsigned
1481 getuid (void)
1482 {
1483 return dflt_passwd.pw_uid;
1484 }
1485
1486 unsigned
1487 geteuid (void)
1488 {
1489 /* I could imagine arguing for checking to see whether the user is
1490 in the Administrators group and returning a UID of 0 for that
1491 case, but I don't know how wise that would be in the long run. */
1492 return getuid ();
1493 }
1494
1495 unsigned
1496 getgid (void)
1497 {
1498 return dflt_passwd.pw_gid;
1499 }
1500
1501 unsigned
1502 getegid (void)
1503 {
1504 return getgid ();
1505 }
1506
1507 struct passwd *
1508 getpwuid (unsigned uid)
1509 {
1510 if (uid == dflt_passwd.pw_uid)
1511 return &dflt_passwd;
1512 return NULL;
1513 }
1514
1515 struct group *
1516 getgrgid (gid_t gid)
1517 {
1518 return &dflt_group;
1519 }
1520
1521 struct passwd *
1522 getpwnam (char *name)
1523 {
1524 struct passwd *pw;
1525
1526 pw = getpwuid (getuid ());
1527 if (!pw)
1528 return pw;
1529
1530 if (xstrcasecmp (name, pw->pw_name))
1531 return NULL;
1532
1533 return pw;
1534 }
1535
1536 static void
1537 init_user_info (void)
1538 {
1539 /* Find the user's real name by opening the process token and
1540 looking up the name associated with the user-sid in that token.
1541
1542 Use the relative portion of the identifier authority value from
1543 the user-sid as the user id value (same for group id using the
1544 primary group sid from the process token). */
1545
1546 char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
1547 DWORD ulength = sizeof (uname), dlength = sizeof (domain), needed;
1548 DWORD glength = sizeof (gname);
1549 HANDLE token = NULL;
1550 SID_NAME_USE user_type;
1551 unsigned char *buf = NULL;
1552 DWORD blen = 0;
1553 TOKEN_USER user_token;
1554 TOKEN_PRIMARY_GROUP group_token;
1555 BOOL result;
1556
1557 result = open_process_token (GetCurrentProcess (), TOKEN_QUERY, &token);
1558 if (result)
1559 {
1560 result = get_token_information (token, TokenUser, NULL, 0, &blen);
1561 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
1562 {
1563 buf = xmalloc (blen);
1564 result = get_token_information (token, TokenUser,
1565 (LPVOID)buf, blen, &needed);
1566 if (result)
1567 {
1568 memcpy (&user_token, buf, sizeof (user_token));
1569 result = lookup_account_sid (NULL, user_token.User.Sid,
1570 uname, &ulength,
1571 domain, &dlength, &user_type);
1572 }
1573 }
1574 else
1575 result = FALSE;
1576 }
1577 if (result)
1578 {
1579 strcpy (dflt_passwd.pw_name, uname);
1580 /* Determine a reasonable uid value. */
1581 if (xstrcasecmp ("administrator", uname) == 0)
1582 {
1583 dflt_passwd.pw_uid = 500; /* well-known Administrator uid */
1584 dflt_passwd.pw_gid = 513; /* well-known None gid */
1585 }
1586 else
1587 {
1588 /* Use the last sub-authority value of the RID, the relative
1589 portion of the SID, as user/group ID. */
1590 dflt_passwd.pw_uid = get_rid (user_token.User.Sid);
1591
1592 /* Get group id and name. */
1593 result = get_token_information (token, TokenPrimaryGroup,
1594 (LPVOID)buf, blen, &needed);
1595 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
1596 {
1597 buf = xrealloc (buf, blen = needed);
1598 result = get_token_information (token, TokenPrimaryGroup,
1599 (LPVOID)buf, blen, &needed);
1600 }
1601 if (result)
1602 {
1603 memcpy (&group_token, buf, sizeof (group_token));
1604 dflt_passwd.pw_gid = get_rid (group_token.PrimaryGroup);
1605 dlength = sizeof (domain);
1606 /* If we can get at the real Primary Group name, use that.
1607 Otherwise, the default group name was already set to
1608 "None" in globals_of_w32. */
1609 if (lookup_account_sid (NULL, group_token.PrimaryGroup,
1610 gname, &glength, NULL, &dlength,
1611 &user_type))
1612 strcpy (dflt_group_name, gname);
1613 }
1614 else
1615 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
1616 }
1617 }
1618 /* If security calls are not supported (presumably because we
1619 are running under Windows 9X), fallback to this: */
1620 else if (GetUserName (uname, &ulength))
1621 {
1622 strcpy (dflt_passwd.pw_name, uname);
1623 if (xstrcasecmp ("administrator", uname) == 0)
1624 dflt_passwd.pw_uid = 0;
1625 else
1626 dflt_passwd.pw_uid = 123;
1627 dflt_passwd.pw_gid = dflt_passwd.pw_uid;
1628 }
1629 else
1630 {
1631 strcpy (dflt_passwd.pw_name, "unknown");
1632 dflt_passwd.pw_uid = 123;
1633 dflt_passwd.pw_gid = 123;
1634 }
1635 dflt_group.gr_gid = dflt_passwd.pw_gid;
1636
1637 /* Ensure HOME and SHELL are defined. */
1638 if (getenv ("HOME") == NULL)
1639 emacs_abort ();
1640 if (getenv ("SHELL") == NULL)
1641 emacs_abort ();
1642
1643 /* Set dir and shell from environment variables. */
1644 strcpy (dflt_passwd.pw_dir, getenv ("HOME"));
1645 strcpy (dflt_passwd.pw_shell, getenv ("SHELL"));
1646
1647 xfree (buf);
1648 if (token)
1649 CloseHandle (token);
1650 }
1651
1652 int
1653 random (void)
1654 {
1655 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
1656 return ((rand () << 15) | rand ());
1657 }
1658
1659 void
1660 srandom (int seed)
1661 {
1662 srand (seed);
1663 }
1664
1665 /* Current codepage for encoding file names. */
1666 static int file_name_codepage;
1667
1668 /* Return the maximum length in bytes of a multibyte character
1669 sequence encoded in the current ANSI codepage. This is required to
1670 correctly walk the encoded file names one character at a time. */
1671 static int
1672 max_filename_mbslen (void)
1673 {
1674 /* A simple cache to avoid calling GetCPInfo every time we need to
1675 normalize a file name. The file-name encoding is not supposed to
1676 be changed too frequently, if ever. */
1677 static Lisp_Object last_file_name_encoding;
1678 static int last_max_mbslen;
1679 Lisp_Object current_encoding;
1680
1681 current_encoding = Vfile_name_coding_system;
1682 if (NILP (current_encoding))
1683 current_encoding = Vdefault_file_name_coding_system;
1684
1685 if (!EQ (last_file_name_encoding, current_encoding))
1686 {
1687 CPINFO cp_info;
1688
1689 last_file_name_encoding = current_encoding;
1690 /* Default to the current ANSI codepage. */
1691 file_name_codepage = w32_ansi_code_page;
1692 if (!NILP (current_encoding))
1693 {
1694 char *cpname = SDATA (SYMBOL_NAME (current_encoding));
1695 char *cp = NULL, *end;
1696 int cpnum;
1697
1698 if (strncmp (cpname, "cp", 2) == 0)
1699 cp = cpname + 2;
1700 else if (strncmp (cpname, "windows-", 8) == 0)
1701 cp = cpname + 8;
1702
1703 if (cp)
1704 {
1705 end = cp;
1706 cpnum = strtol (cp, &end, 10);
1707 if (cpnum && *end == '\0' && end - cp >= 2)
1708 file_name_codepage = cpnum;
1709 }
1710 }
1711
1712 if (!file_name_codepage)
1713 file_name_codepage = CP_ACP; /* CP_ACP = 0, but let's not assume that */
1714
1715 if (!GetCPInfo (file_name_codepage, &cp_info))
1716 {
1717 file_name_codepage = CP_ACP;
1718 if (!GetCPInfo (file_name_codepage, &cp_info))
1719 emacs_abort ();
1720 }
1721 last_max_mbslen = cp_info.MaxCharSize;
1722 }
1723
1724 return last_max_mbslen;
1725 }
1726
1727 /* Normalize filename by converting all path separators to
1728 the specified separator. Also conditionally convert upper
1729 case path name components to lower case. */
1730
1731 static void
1732 normalize_filename (register char *fp, char path_sep, int multibyte)
1733 {
1734 char sep;
1735 char *elem, *p2;
1736 int dbcs_p = max_filename_mbslen () > 1;
1737
1738 /* Multibyte file names are in the Emacs internal representation, so
1739 we can traverse them by bytes with no problems. */
1740 if (multibyte)
1741 dbcs_p = 0;
1742
1743 /* Always lower-case drive letters a-z, even if the filesystem
1744 preserves case in filenames.
1745 This is so filenames can be compared by string comparison
1746 functions that are case-sensitive. Even case-preserving filesystems
1747 do not distinguish case in drive letters. */
1748 if (dbcs_p)
1749 p2 = CharNextExA (file_name_codepage, fp, 0);
1750 else
1751 p2 = fp + 1;
1752
1753 if (*p2 == ':' && *fp >= 'A' && *fp <= 'Z')
1754 {
1755 *fp += 'a' - 'A';
1756 fp += 2;
1757 }
1758
1759 if (multibyte || NILP (Vw32_downcase_file_names))
1760 {
1761 while (*fp)
1762 {
1763 if (*fp == '/' || *fp == '\\')
1764 *fp = path_sep;
1765 if (!dbcs_p)
1766 fp++;
1767 else
1768 fp = CharNextExA (file_name_codepage, fp, 0);
1769 }
1770 return;
1771 }
1772
1773 sep = path_sep; /* convert to this path separator */
1774 elem = fp; /* start of current path element */
1775
1776 do {
1777 if (*fp >= 'a' && *fp <= 'z')
1778 elem = 0; /* don't convert this element */
1779
1780 if (*fp == 0 || *fp == ':')
1781 {
1782 sep = *fp; /* restore current separator (or 0) */
1783 *fp = '/'; /* after conversion of this element */
1784 }
1785
1786 if (*fp == '/' || *fp == '\\')
1787 {
1788 if (elem && elem != fp)
1789 {
1790 *fp = 0; /* temporary end of string */
1791 _mbslwr (elem); /* while we convert to lower case */
1792 }
1793 *fp = sep; /* convert (or restore) path separator */
1794 elem = fp + 1; /* next element starts after separator */
1795 sep = path_sep;
1796 }
1797 if (*fp)
1798 {
1799 if (!dbcs_p)
1800 fp++;
1801 else
1802 fp = CharNextExA (file_name_codepage, fp, 0);
1803 }
1804 } while (*fp);
1805 }
1806
1807 /* Destructively turn backslashes into slashes. MULTIBYTE non-zero
1808 means the file name is a multibyte string in Emacs's internal
1809 representation. */
1810 void
1811 dostounix_filename (register char *p, int multibyte)
1812 {
1813 normalize_filename (p, '/', multibyte);
1814 }
1815
1816 /* Destructively turn slashes into backslashes. */
1817 void
1818 unixtodos_filename (register char *p)
1819 {
1820 normalize_filename (p, '\\', 0);
1821 }
1822
1823 /* Remove all CR's that are followed by a LF.
1824 (From msdos.c...probably should figure out a way to share it,
1825 although this code isn't going to ever change.) */
1826 static int
1827 crlf_to_lf (register int n, register unsigned char *buf)
1828 {
1829 unsigned char *np = buf;
1830 unsigned char *startp = buf;
1831 unsigned char *endp = buf + n;
1832
1833 if (n == 0)
1834 return n;
1835 while (buf < endp - 1)
1836 {
1837 if (*buf == 0x0d)
1838 {
1839 if (*(++buf) != 0x0a)
1840 *np++ = 0x0d;
1841 }
1842 else
1843 *np++ = *buf++;
1844 }
1845 if (buf < endp)
1846 *np++ = *buf++;
1847 return np - startp;
1848 }
1849
1850 /* Parse the root part of file name, if present. Return length and
1851 optionally store pointer to char after root. */
1852 static int
1853 parse_root (char * name, char ** pPath)
1854 {
1855 char * start = name;
1856
1857 if (name == NULL)
1858 return 0;
1859
1860 /* find the root name of the volume if given */
1861 if (isalpha (name[0]) && name[1] == ':')
1862 {
1863 /* skip past drive specifier */
1864 name += 2;
1865 if (IS_DIRECTORY_SEP (name[0]))
1866 name++;
1867 }
1868 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
1869 {
1870 int slashes = 2;
1871 int dbcs_p = max_filename_mbslen () > 1;
1872
1873 name += 2;
1874 do
1875 {
1876 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
1877 break;
1878 if (dbcs_p)
1879 name = CharNextExA (file_name_codepage, name, 0);
1880 else
1881 name++;
1882 }
1883 while ( *name );
1884 if (IS_DIRECTORY_SEP (name[0]))
1885 name++;
1886 }
1887
1888 if (pPath)
1889 *pPath = name;
1890
1891 return name - start;
1892 }
1893
1894 /* Get long base name for name; name is assumed to be absolute. */
1895 static int
1896 get_long_basename (char * name, char * buf, int size)
1897 {
1898 WIN32_FIND_DATA find_data;
1899 HANDLE dir_handle;
1900 int len = 0;
1901
1902 /* must be valid filename, no wild cards or other invalid characters */
1903 if (_mbspbrk (name, "*?|<>\""))
1904 return 0;
1905
1906 dir_handle = FindFirstFile (name, &find_data);
1907 if (dir_handle != INVALID_HANDLE_VALUE)
1908 {
1909 if ((len = strlen (find_data.cFileName)) < size)
1910 memcpy (buf, find_data.cFileName, len + 1);
1911 else
1912 len = 0;
1913 FindClose (dir_handle);
1914 }
1915 return len;
1916 }
1917
1918 /* Get long name for file, if possible (assumed to be absolute). */
1919 BOOL
1920 w32_get_long_filename (char * name, char * buf, int size)
1921 {
1922 char * o = buf;
1923 char * p;
1924 char * q;
1925 char full[ MAX_PATH ];
1926 int len;
1927
1928 len = strlen (name);
1929 if (len >= MAX_PATH)
1930 return FALSE;
1931
1932 /* Use local copy for destructive modification. */
1933 memcpy (full, name, len+1);
1934 unixtodos_filename (full);
1935
1936 /* Copy root part verbatim. */
1937 len = parse_root (full, &p);
1938 memcpy (o, full, len);
1939 o += len;
1940 *o = '\0';
1941 size -= len;
1942
1943 while (p != NULL && *p)
1944 {
1945 q = p;
1946 p = _mbschr (q, '\\');
1947 if (p) *p = '\0';
1948 len = get_long_basename (full, o, size);
1949 if (len > 0)
1950 {
1951 o += len;
1952 size -= len;
1953 if (p != NULL)
1954 {
1955 *p++ = '\\';
1956 if (size < 2)
1957 return FALSE;
1958 *o++ = '\\';
1959 size--;
1960 *o = '\0';
1961 }
1962 }
1963 else
1964 return FALSE;
1965 }
1966
1967 return TRUE;
1968 }
1969
1970 static int
1971 is_unc_volume (const char *filename)
1972 {
1973 const char *ptr = filename;
1974
1975 if (!IS_DIRECTORY_SEP (ptr[0]) || !IS_DIRECTORY_SEP (ptr[1]) || !ptr[2])
1976 return 0;
1977
1978 if (_mbspbrk (ptr + 2, "*?|<>\"\\/"))
1979 return 0;
1980
1981 return 1;
1982 }
1983
1984 /* Emulate the Posix unsetenv. */
1985 int
1986 unsetenv (const char *name)
1987 {
1988 char *var;
1989 size_t name_len;
1990 int retval;
1991
1992 if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
1993 {
1994 errno = EINVAL;
1995 return -1;
1996 }
1997 name_len = strlen (name);
1998 /* MS docs says an environment variable cannot be longer than 32K. */
1999 if (name_len > 32767)
2000 {
2001 errno = ENOMEM;
2002 return 0;
2003 }
2004 /* It is safe to use 'alloca' with 32K size, since the stack is at
2005 least 2MB, and we set it to 8MB in the link command line. */
2006 var = alloca (name_len + 2);
2007 strncpy (var, name, name_len);
2008 var[name_len++] = '=';
2009 var[name_len] = '\0';
2010 return _putenv (var);
2011 }
2012
2013 /* MS _putenv doesn't support removing a variable when the argument
2014 does not include the '=' character, so we fix that here. */
2015 int
2016 sys_putenv (char *str)
2017 {
2018 const char *const name_end = strchr (str, '=');
2019
2020 if (name_end == NULL)
2021 {
2022 /* Remove the variable from the environment. */
2023 return unsetenv (str);
2024 }
2025
2026 return _putenv (str);
2027 }
2028
2029 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
2030
2031 LPBYTE
2032 w32_get_resource (char *key, LPDWORD lpdwtype)
2033 {
2034 LPBYTE lpvalue;
2035 HKEY hrootkey = NULL;
2036 DWORD cbData;
2037
2038 /* Check both the current user and the local machine to see if
2039 we have any resources. */
2040
2041 if (RegOpenKeyEx (HKEY_CURRENT_USER, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
2042 {
2043 lpvalue = NULL;
2044
2045 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
2046 && (lpvalue = xmalloc (cbData)) != NULL
2047 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
2048 {
2049 RegCloseKey (hrootkey);
2050 return (lpvalue);
2051 }
2052
2053 xfree (lpvalue);
2054
2055 RegCloseKey (hrootkey);
2056 }
2057
2058 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
2059 {
2060 lpvalue = NULL;
2061
2062 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
2063 && (lpvalue = xmalloc (cbData)) != NULL
2064 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
2065 {
2066 RegCloseKey (hrootkey);
2067 return (lpvalue);
2068 }
2069
2070 xfree (lpvalue);
2071
2072 RegCloseKey (hrootkey);
2073 }
2074
2075 return (NULL);
2076 }
2077
2078 char *get_emacs_configuration (void);
2079
2080 void
2081 init_environment (char ** argv)
2082 {
2083 static const char * const tempdirs[] = {
2084 "$TMPDIR", "$TEMP", "$TMP", "c:/"
2085 };
2086
2087 int i;
2088
2089 const int imax = sizeof (tempdirs) / sizeof (tempdirs[0]);
2090
2091 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
2092 temporary files and assume "/tmp" if $TMPDIR is unset, which
2093 will break on DOS/Windows. Refuse to work if we cannot find
2094 a directory, not even "c:/", usable for that purpose. */
2095 for (i = 0; i < imax ; i++)
2096 {
2097 const char *tmp = tempdirs[i];
2098
2099 if (*tmp == '$')
2100 tmp = getenv (tmp + 1);
2101 /* Note that `access' can lie to us if the directory resides on a
2102 read-only filesystem, like CD-ROM or a write-protected floppy.
2103 The only way to be really sure is to actually create a file and
2104 see if it succeeds. But I think that's too much to ask. */
2105
2106 /* MSVCRT's _access crashes with D_OK. */
2107 if (tmp && faccessat (AT_FDCWD, tmp, D_OK, AT_EACCESS) == 0)
2108 {
2109 char * var = alloca (strlen (tmp) + 8);
2110 sprintf (var, "TMPDIR=%s", tmp);
2111 _putenv (strdup (var));
2112 break;
2113 }
2114 }
2115 if (i >= imax)
2116 cmd_error_internal
2117 (Fcons (Qerror,
2118 Fcons (build_string ("no usable temporary directories found!!"),
2119 Qnil)),
2120 "While setting TMPDIR: ");
2121
2122 /* Check for environment variables and use registry settings if they
2123 don't exist. Fallback on default values where applicable. */
2124 {
2125 int i;
2126 LPBYTE lpval;
2127 DWORD dwType;
2128 char locale_name[32];
2129 char default_home[MAX_PATH];
2130 int appdata = 0;
2131
2132 static const struct env_entry
2133 {
2134 char * name;
2135 char * def_value;
2136 } dflt_envvars[] =
2137 {
2138 /* If the default value is NULL, we will use the value from the
2139 outside environment or the Registry, but will not push the
2140 variable into the Emacs environment if it is defined neither
2141 in the Registry nor in the outside environment. */
2142 {"HOME", "C:/"},
2143 {"PRELOAD_WINSOCK", NULL},
2144 {"emacs_dir", "C:/emacs"},
2145 {"EMACSLOADPATH", NULL},
2146 {"SHELL", "cmdproxy.exe"}, /* perhaps it is somewhere on PATH */
2147 {"EMACSDATA", NULL},
2148 {"EMACSPATH", NULL},
2149 {"INFOPATH", NULL},
2150 {"EMACSDOC", NULL},
2151 {"TERM", "cmd"},
2152 {"LANG", NULL},
2153 };
2154
2155 #define N_ENV_VARS sizeof (dflt_envvars)/sizeof (dflt_envvars[0])
2156
2157 /* We need to copy dflt_envvars[] and work on the copy because we
2158 don't want the dumped Emacs to inherit the values of
2159 environment variables we saw during dumping (which could be on
2160 a different system). The defaults above must be left intact. */
2161 struct env_entry env_vars[N_ENV_VARS];
2162
2163 for (i = 0; i < N_ENV_VARS; i++)
2164 env_vars[i] = dflt_envvars[i];
2165
2166 /* For backwards compatibility, check if a .emacs file exists in C:/
2167 If not, then we can try to default to the appdata directory under the
2168 user's profile, which is more likely to be writable. */
2169 if (faccessat (AT_FDCWD, "C:/.emacs", F_OK, AT_EACCESS) != 0)
2170 {
2171 HRESULT profile_result;
2172 /* Dynamically load ShGetFolderPath, as it won't exist on versions
2173 of Windows 95 and NT4 that have not been updated to include
2174 MSIE 5. */
2175 ShGetFolderPath_fn get_folder_path;
2176 get_folder_path = (ShGetFolderPath_fn)
2177 GetProcAddress (GetModuleHandle ("shell32.dll"), "SHGetFolderPathA");
2178
2179 if (get_folder_path != NULL)
2180 {
2181 profile_result = get_folder_path (NULL, CSIDL_APPDATA, NULL,
2182 0, default_home);
2183
2184 /* If we can't get the appdata dir, revert to old behavior. */
2185 if (profile_result == S_OK)
2186 {
2187 env_vars[0].def_value = default_home;
2188 appdata = 1;
2189 }
2190 }
2191 }
2192
2193 /* Get default locale info and use it for LANG. */
2194 if (GetLocaleInfo (LOCALE_USER_DEFAULT,
2195 LOCALE_SABBREVLANGNAME | LOCALE_USE_CP_ACP,
2196 locale_name, sizeof (locale_name)))
2197 {
2198 for (i = 0; i < N_ENV_VARS; i++)
2199 {
2200 if (strcmp (env_vars[i].name, "LANG") == 0)
2201 {
2202 env_vars[i].def_value = locale_name;
2203 break;
2204 }
2205 }
2206 }
2207
2208 #define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
2209
2210 /* Treat emacs_dir specially: set it unconditionally based on our
2211 location. */
2212 {
2213 char *p;
2214 char modname[MAX_PATH];
2215
2216 if (!GetModuleFileName (NULL, modname, MAX_PATH))
2217 emacs_abort ();
2218 if ((p = _mbsrchr (modname, '\\')) == NULL)
2219 emacs_abort ();
2220 *p = 0;
2221
2222 if ((p = _mbsrchr (modname, '\\'))
2223 /* From bin means installed Emacs, from src means uninstalled. */
2224 && (xstrcasecmp (p, "\\bin") == 0 || xstrcasecmp (p, "\\src") == 0))
2225 {
2226 char buf[SET_ENV_BUF_SIZE];
2227 int within_build_tree = xstrcasecmp (p, "\\src") == 0;
2228
2229 *p = 0;
2230 for (p = modname; *p; p = CharNext (p))
2231 if (*p == '\\') *p = '/';
2232
2233 _snprintf (buf, sizeof (buf)-1, "emacs_dir=%s", modname);
2234 _putenv (strdup (buf));
2235 /* If we are running from the Posix-like build tree, define
2236 SHELL to point to our own cmdproxy. The loop below will
2237 then disregard PATH_EXEC and the default value. */
2238 if (within_build_tree)
2239 {
2240 _snprintf (buf, sizeof (buf) - 1,
2241 "SHELL=%s/nt/cmdproxy.exe", modname);
2242 _putenv (strdup (buf));
2243 }
2244 }
2245 /* Handle running emacs from the build directory: src/oo-spd/i386/ */
2246
2247 /* FIXME: should use substring of get_emacs_configuration ().
2248 But I don't think the Windows build supports alpha, mips etc
2249 anymore, so have taken the easy option for now. */
2250 else if (p && (xstrcasecmp (p, "\\i386") == 0
2251 || xstrcasecmp (p, "\\AMD64") == 0))
2252 {
2253 *p = 0;
2254 p = _mbsrchr (modname, '\\');
2255 if (p != NULL)
2256 {
2257 *p = 0;
2258 p = _mbsrchr (modname, '\\');
2259 if (p && xstrcasecmp (p, "\\src") == 0)
2260 {
2261 char buf[SET_ENV_BUF_SIZE];
2262
2263 *p = 0;
2264 for (p = modname; *p; p = CharNext (p))
2265 if (*p == '\\') *p = '/';
2266
2267 _snprintf (buf, sizeof (buf)-1, "emacs_dir=%s", modname);
2268 _putenv (strdup (buf));
2269 }
2270 }
2271 }
2272 }
2273
2274 for (i = 0; i < N_ENV_VARS; i++)
2275 {
2276 if (!getenv (env_vars[i].name))
2277 {
2278 int dont_free = 0;
2279 char bufc[SET_ENV_BUF_SIZE];
2280
2281 if ((lpval = w32_get_resource (env_vars[i].name, &dwType)) == NULL
2282 /* Also ignore empty environment variables. */
2283 || *lpval == 0)
2284 {
2285 xfree (lpval);
2286 dont_free = 1;
2287 if (strcmp (env_vars[i].name, "SHELL") == 0)
2288 {
2289 /* Look for cmdproxy.exe in every directory in
2290 PATH_EXEC. FIXME: This does not find cmdproxy
2291 in nt/ when we run uninstalled. */
2292 char fname[MAX_PATH];
2293 const char *pstart = PATH_EXEC, *pend;
2294
2295 do {
2296 pend = _mbschr (pstart, ';');
2297 if (!pend)
2298 pend = pstart + strlen (pstart);
2299 /* Be defensive against series of ;;; characters. */
2300 if (pend > pstart)
2301 {
2302 strncpy (fname, pstart, pend - pstart);
2303 fname[pend - pstart] = '/';
2304 strcpy (&fname[pend - pstart + 1], "cmdproxy.exe");
2305 ExpandEnvironmentStrings ((LPSTR) fname, bufc,
2306 sizeof (bufc));
2307 if (faccessat (AT_FDCWD, bufc, F_OK, AT_EACCESS)
2308 == 0)
2309 {
2310 lpval = bufc;
2311 dwType = REG_SZ;
2312 break;
2313 }
2314 }
2315 if (*pend)
2316 pstart = pend + 1;
2317 else
2318 pstart = pend;
2319 if (!*pstart)
2320 {
2321 /* If not found in any directory, use the
2322 default as the last resort. */
2323 lpval = env_vars[i].def_value;
2324 dwType = REG_EXPAND_SZ;
2325 }
2326 } while (*pstart);
2327 }
2328 else
2329 {
2330 lpval = env_vars[i].def_value;
2331 dwType = REG_EXPAND_SZ;
2332 }
2333 if (strcmp (env_vars[i].name, "HOME") == 0 && !appdata)
2334 Vdelayed_warnings_list
2335 = Fcons (listn (CONSTYPE_HEAP, 2,
2336 intern ("initialization"),
2337 build_string ("Setting HOME to C:\\ by default is deprecated")),
2338 Vdelayed_warnings_list);
2339 }
2340
2341 if (lpval)
2342 {
2343 char buf1[SET_ENV_BUF_SIZE], buf2[SET_ENV_BUF_SIZE];
2344
2345 if (dwType == REG_EXPAND_SZ)
2346 ExpandEnvironmentStrings ((LPSTR) lpval, buf1, sizeof (buf1));
2347 else if (dwType == REG_SZ)
2348 strcpy (buf1, lpval);
2349 if (dwType == REG_EXPAND_SZ || dwType == REG_SZ)
2350 {
2351 _snprintf (buf2, sizeof (buf2)-1, "%s=%s", env_vars[i].name,
2352 buf1);
2353 _putenv (strdup (buf2));
2354 }
2355
2356 if (!dont_free)
2357 xfree (lpval);
2358 }
2359 }
2360 }
2361 }
2362
2363 /* Rebuild system configuration to reflect invoking system. */
2364 Vsystem_configuration = build_string (EMACS_CONFIGURATION);
2365
2366 /* Another special case: on NT, the PATH variable is actually named
2367 "Path" although cmd.exe (perhaps NT itself) arranges for
2368 environment variable lookup and setting to be case insensitive.
2369 However, Emacs assumes a fully case sensitive environment, so we
2370 need to change "Path" to "PATH" to match the expectations of
2371 various elisp packages. We do this by the sneaky method of
2372 modifying the string in the C runtime environ entry.
2373
2374 The same applies to COMSPEC. */
2375 {
2376 char ** envp;
2377
2378 for (envp = environ; *envp; envp++)
2379 if (_strnicmp (*envp, "PATH=", 5) == 0)
2380 memcpy (*envp, "PATH=", 5);
2381 else if (_strnicmp (*envp, "COMSPEC=", 8) == 0)
2382 memcpy (*envp, "COMSPEC=", 8);
2383 }
2384
2385 /* Remember the initial working directory for getcwd. */
2386 /* FIXME: Do we need to resolve possible symlinks in startup_dir?
2387 Does it matter anywhere in Emacs? */
2388 if (!GetCurrentDirectory (MAXPATHLEN, startup_dir))
2389 emacs_abort ();
2390
2391 {
2392 static char modname[MAX_PATH];
2393
2394 if (!GetModuleFileName (NULL, modname, MAX_PATH))
2395 emacs_abort ();
2396 argv[0] = modname;
2397 }
2398
2399 /* Determine if there is a middle mouse button, to allow parse_button
2400 to decide whether right mouse events should be mouse-2 or
2401 mouse-3. */
2402 w32_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);
2403
2404 init_user_info ();
2405 }
2406
2407 /* Called from expand-file-name when default-directory is not a string. */
2408
2409 char *
2410 emacs_root_dir (void)
2411 {
2412 static char root_dir[FILENAME_MAX];
2413 const char *p;
2414
2415 p = getenv ("emacs_dir");
2416 if (p == NULL)
2417 emacs_abort ();
2418 strcpy (root_dir, p);
2419 root_dir[parse_root (root_dir, NULL)] = '\0';
2420 dostounix_filename (root_dir, 0);
2421 return root_dir;
2422 }
2423
2424 /* We don't have scripts to automatically determine the system configuration
2425 for Emacs before it's compiled, and we don't want to have to make the
2426 user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
2427 routine. */
2428
2429 char *
2430 get_emacs_configuration (void)
2431 {
2432 char *arch, *oem, *os;
2433 int build_num;
2434 static char configuration_buffer[32];
2435
2436 /* Determine the processor type. */
2437 switch (get_processor_type ())
2438 {
2439
2440 #ifdef PROCESSOR_INTEL_386
2441 case PROCESSOR_INTEL_386:
2442 case PROCESSOR_INTEL_486:
2443 case PROCESSOR_INTEL_PENTIUM:
2444 #ifdef _WIN64
2445 arch = "amd64";
2446 #else
2447 arch = "i386";
2448 #endif
2449 break;
2450 #endif
2451 #ifdef PROCESSOR_AMD_X8664
2452 case PROCESSOR_AMD_X8664:
2453 arch = "amd64";
2454 break;
2455 #endif
2456
2457 #ifdef PROCESSOR_MIPS_R2000
2458 case PROCESSOR_MIPS_R2000:
2459 case PROCESSOR_MIPS_R3000:
2460 case PROCESSOR_MIPS_R4000:
2461 arch = "mips";
2462 break;
2463 #endif
2464
2465 #ifdef PROCESSOR_ALPHA_21064
2466 case PROCESSOR_ALPHA_21064:
2467 arch = "alpha";
2468 break;
2469 #endif
2470
2471 default:
2472 arch = "unknown";
2473 break;
2474 }
2475
2476 /* Use the OEM field to reflect the compiler/library combination. */
2477 #ifdef _MSC_VER
2478 #define COMPILER_NAME "msvc"
2479 #else
2480 #ifdef __GNUC__
2481 #define COMPILER_NAME "mingw"
2482 #else
2483 #define COMPILER_NAME "unknown"
2484 #endif
2485 #endif
2486 oem = COMPILER_NAME;
2487
2488 switch (osinfo_cache.dwPlatformId) {
2489 case VER_PLATFORM_WIN32_NT:
2490 os = "nt";
2491 build_num = osinfo_cache.dwBuildNumber;
2492 break;
2493 case VER_PLATFORM_WIN32_WINDOWS:
2494 if (osinfo_cache.dwMinorVersion == 0) {
2495 os = "windows95";
2496 } else {
2497 os = "windows98";
2498 }
2499 build_num = LOWORD (osinfo_cache.dwBuildNumber);
2500 break;
2501 case VER_PLATFORM_WIN32s:
2502 /* Not supported, should not happen. */
2503 os = "windows32s";
2504 build_num = LOWORD (osinfo_cache.dwBuildNumber);
2505 break;
2506 default:
2507 os = "unknown";
2508 build_num = 0;
2509 break;
2510 }
2511
2512 if (osinfo_cache.dwPlatformId == VER_PLATFORM_WIN32_NT) {
2513 sprintf (configuration_buffer, "%s-%s-%s%d.%d.%d", arch, oem, os,
2514 get_w32_major_version (), get_w32_minor_version (), build_num);
2515 } else {
2516 sprintf (configuration_buffer, "%s-%s-%s.%d", arch, oem, os, build_num);
2517 }
2518
2519 return configuration_buffer;
2520 }
2521
2522 char *
2523 get_emacs_configuration_options (void)
2524 {
2525 static char *options_buffer;
2526 char cv[32]; /* Enough for COMPILER_VERSION. */
2527 char *options[] = {
2528 cv, /* To be filled later. */
2529 #ifdef EMACSDEBUG
2530 " --no-opt",
2531 #endif
2532 #ifdef ENABLE_CHECKING
2533 " --enable-checking",
2534 #endif
2535 /* configure.bat already sets USER_CFLAGS and USER_LDFLAGS
2536 with a starting space to save work here. */
2537 #ifdef USER_CFLAGS
2538 " --cflags", USER_CFLAGS,
2539 #endif
2540 #ifdef USER_LDFLAGS
2541 " --ldflags", USER_LDFLAGS,
2542 #endif
2543 NULL
2544 };
2545 size_t size = 0;
2546 int i;
2547
2548 /* Work out the effective configure options for this build. */
2549 #ifdef _MSC_VER
2550 #define COMPILER_VERSION "--with-msvc (%d.%02d)", _MSC_VER / 100, _MSC_VER % 100
2551 #else
2552 #ifdef __GNUC__
2553 #define COMPILER_VERSION "--with-gcc (%d.%d)", __GNUC__, __GNUC_MINOR__
2554 #else
2555 #define COMPILER_VERSION ""
2556 #endif
2557 #endif
2558
2559 if (_snprintf (cv, sizeof (cv) - 1, COMPILER_VERSION) < 0)
2560 return "Error: not enough space for compiler version";
2561 cv[sizeof (cv) - 1] = '\0';
2562
2563 for (i = 0; options[i]; i++)
2564 size += strlen (options[i]);
2565
2566 options_buffer = xmalloc (size + 1);
2567 options_buffer[0] = '\0';
2568
2569 for (i = 0; options[i]; i++)
2570 strcat (options_buffer, options[i]);
2571
2572 return options_buffer;
2573 }
2574
2575
2576 #include <sys/timeb.h>
2577
2578 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
2579 int
2580 gettimeofday (struct timeval *__restrict tv, struct timezone *__restrict tz)
2581 {
2582 struct _timeb tb;
2583 _ftime (&tb);
2584
2585 tv->tv_sec = tb.time;
2586 tv->tv_usec = tb.millitm * 1000L;
2587 /* Implementation note: _ftime sometimes doesn't update the dstflag
2588 according to the new timezone when the system timezone is
2589 changed. We could fix that by using GetSystemTime and
2590 GetTimeZoneInformation, but that doesn't seem necessary, since
2591 Emacs always calls gettimeofday with the 2nd argument NULL (see
2592 current_emacs_time). */
2593 if (tz)
2594 {
2595 tz->tz_minuteswest = tb.timezone; /* minutes west of Greenwich */
2596 tz->tz_dsttime = tb.dstflag; /* type of dst correction */
2597 }
2598 return 0;
2599 }
2600
2601 /* Emulate fdutimens. */
2602
2603 /* Set the access and modification time stamps of FD (a.k.a. FILE) to be
2604 TIMESPEC[0] and TIMESPEC[1], respectively.
2605 FD must be either negative -- in which case it is ignored --
2606 or a file descriptor that is open on FILE.
2607 If FD is nonnegative, then FILE can be NULL, which means
2608 use just futimes instead of utimes.
2609 If TIMESPEC is null, FAIL.
2610 Return 0 on success, -1 (setting errno) on failure. */
2611
2612 int
2613 fdutimens (int fd, char const *file, struct timespec const timespec[2])
2614 {
2615 if (!timespec)
2616 {
2617 errno = ENOSYS;
2618 return -1;
2619 }
2620 if (fd < 0 && !file)
2621 {
2622 errno = EBADF;
2623 return -1;
2624 }
2625 /* _futime's prototype defines 2nd arg as having the type 'struct
2626 _utimbuf', while utime needs to accept 'struct utimbuf' for
2627 compatibility with Posix. So we need to use 2 different (but
2628 equivalent) types to avoid compiler warnings, sigh. */
2629 if (fd >= 0)
2630 {
2631 struct _utimbuf _ut;
2632
2633 _ut.actime = timespec[0].tv_sec;
2634 _ut.modtime = timespec[1].tv_sec;
2635 return _futime (fd, &_ut);
2636 }
2637 else
2638 {
2639 struct utimbuf ut;
2640
2641 ut.actime = timespec[0].tv_sec;
2642 ut.modtime = timespec[1].tv_sec;
2643 /* Call 'utime', which is implemented below, not the MS library
2644 function, which fails on directories. */
2645 return utime (file, &ut);
2646 }
2647 }
2648
2649
2650 /* ------------------------------------------------------------------------- */
2651 /* IO support and wrapper functions for the Windows API. */
2652 /* ------------------------------------------------------------------------- */
2653
2654 /* Place a wrapper around the MSVC version of ctime. It returns NULL
2655 on network directories, so we handle that case here.
2656 (Ulrich Leodolter, 1/11/95). */
2657 char *
2658 sys_ctime (const time_t *t)
2659 {
2660 char *str = (char *) ctime (t);
2661 return (str ? str : "Sun Jan 01 00:00:00 1970");
2662 }
2663
2664 /* Emulate sleep...we could have done this with a define, but that
2665 would necessitate including windows.h in the files that used it.
2666 This is much easier. */
2667 void
2668 sys_sleep (int seconds)
2669 {
2670 Sleep (seconds * 1000);
2671 }
2672
2673 /* Internal MSVC functions for low-level descriptor munging */
2674 extern int __cdecl _set_osfhnd (int fd, long h);
2675 extern int __cdecl _free_osfhnd (int fd);
2676
2677 /* parallel array of private info on file handles */
2678 filedesc fd_info [ MAXDESC ];
2679
2680 typedef struct volume_info_data {
2681 struct volume_info_data * next;
2682
2683 /* time when info was obtained */
2684 DWORD timestamp;
2685
2686 /* actual volume info */
2687 char * root_dir;
2688 DWORD serialnum;
2689 DWORD maxcomp;
2690 DWORD flags;
2691 char * name;
2692 char * type;
2693 } volume_info_data;
2694
2695 /* Global referenced by various functions. */
2696 static volume_info_data volume_info;
2697
2698 /* Vector to indicate which drives are local and fixed (for which cached
2699 data never expires). */
2700 static BOOL fixed_drives[26];
2701
2702 /* Consider cached volume information to be stale if older than 10s,
2703 at least for non-local drives. Info for fixed drives is never stale. */
2704 #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
2705 #define VOLINFO_STILL_VALID( root_dir, info ) \
2706 ( ( isalpha (root_dir[0]) && \
2707 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
2708 || GetTickCount () - info->timestamp < 10000 )
2709
2710 /* Cache support functions. */
2711
2712 /* Simple linked list with linear search is sufficient. */
2713 static volume_info_data *volume_cache = NULL;
2714
2715 static volume_info_data *
2716 lookup_volume_info (char * root_dir)
2717 {
2718 volume_info_data * info;
2719
2720 for (info = volume_cache; info; info = info->next)
2721 if (xstrcasecmp (info->root_dir, root_dir) == 0)
2722 break;
2723 return info;
2724 }
2725
2726 static void
2727 add_volume_info (char * root_dir, volume_info_data * info)
2728 {
2729 info->root_dir = xstrdup (root_dir);
2730 info->next = volume_cache;
2731 volume_cache = info;
2732 }
2733
2734
2735 /* Wrapper for GetVolumeInformation, which uses caching to avoid
2736 performance penalty (~2ms on 486 for local drives, 7.5ms for local
2737 cdrom drive, ~5-10ms or more for remote drives on LAN). */
2738 static volume_info_data *
2739 GetCachedVolumeInformation (char * root_dir)
2740 {
2741 volume_info_data * info;
2742 char default_root[ MAX_PATH ];
2743
2744 /* NULL for root_dir means use root from current directory. */
2745 if (root_dir == NULL)
2746 {
2747 if (GetCurrentDirectory (MAX_PATH, default_root) == 0)
2748 return NULL;
2749 parse_root (default_root, &root_dir);
2750 *root_dir = 0;
2751 root_dir = default_root;
2752 }
2753
2754 /* Local fixed drives can be cached permanently. Removable drives
2755 cannot be cached permanently, since the volume name and serial
2756 number (if nothing else) can change. Remote drives should be
2757 treated as if they are removable, since there is no sure way to
2758 tell whether they are or not. Also, the UNC association of drive
2759 letters mapped to remote volumes can be changed at any time (even
2760 by other processes) without notice.
2761
2762 As a compromise, so we can benefit from caching info for remote
2763 volumes, we use a simple expiry mechanism to invalidate cache
2764 entries that are more than ten seconds old. */
2765
2766 #if 0
2767 /* No point doing this, because WNetGetConnection is even slower than
2768 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
2769 GetDriveType is about the only call of this type which does not
2770 involve network access, and so is extremely quick). */
2771
2772 /* Map drive letter to UNC if remote. */
2773 if (isalpha (root_dir[0]) && !fixed[DRIVE_INDEX (root_dir[0])])
2774 {
2775 char remote_name[ 256 ];
2776 char drive[3] = { root_dir[0], ':' };
2777
2778 if (WNetGetConnection (drive, remote_name, sizeof (remote_name))
2779 == NO_ERROR)
2780 /* do something */ ;
2781 }
2782 #endif
2783
2784 info = lookup_volume_info (root_dir);
2785
2786 if (info == NULL || ! VOLINFO_STILL_VALID (root_dir, info))
2787 {
2788 char name[ 256 ];
2789 DWORD serialnum;
2790 DWORD maxcomp;
2791 DWORD flags;
2792 char type[ 256 ];
2793
2794 /* Info is not cached, or is stale. */
2795 if (!GetVolumeInformation (root_dir,
2796 name, sizeof (name),
2797 &serialnum,
2798 &maxcomp,
2799 &flags,
2800 type, sizeof (type)))
2801 return NULL;
2802
2803 /* Cache the volume information for future use, overwriting existing
2804 entry if present. */
2805 if (info == NULL)
2806 {
2807 info = xmalloc (sizeof (volume_info_data));
2808 add_volume_info (root_dir, info);
2809 }
2810 else
2811 {
2812 xfree (info->name);
2813 xfree (info->type);
2814 }
2815
2816 info->name = xstrdup (name);
2817 info->serialnum = serialnum;
2818 info->maxcomp = maxcomp;
2819 info->flags = flags;
2820 info->type = xstrdup (type);
2821 info->timestamp = GetTickCount ();
2822 }
2823
2824 return info;
2825 }
2826
2827 /* Get information on the volume where NAME is held; set path pointer to
2828 start of pathname in NAME (past UNC header\volume header if present),
2829 if pPath is non-NULL.
2830
2831 Note: if NAME includes symlinks, the information is for the volume
2832 of the symlink, not of its target. That's because, even though
2833 GetVolumeInformation returns information about the symlink target
2834 of its argument, we only pass the root directory to
2835 GetVolumeInformation, not the full NAME. */
2836 static int
2837 get_volume_info (const char * name, const char ** pPath)
2838 {
2839 char temp[MAX_PATH];
2840 char *rootname = NULL; /* default to current volume */
2841 volume_info_data * info;
2842
2843 if (name == NULL)
2844 return FALSE;
2845
2846 /* Find the root name of the volume if given. */
2847 if (isalpha (name[0]) && name[1] == ':')
2848 {
2849 rootname = temp;
2850 temp[0] = *name++;
2851 temp[1] = *name++;
2852 temp[2] = '\\';
2853 temp[3] = 0;
2854 }
2855 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
2856 {
2857 char *str = temp;
2858 int slashes = 4;
2859 int dbcs_p = max_filename_mbslen () > 1;
2860
2861 rootname = temp;
2862 do
2863 {
2864 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
2865 break;
2866 if (!dbcs_p)
2867 *str++ = *name++;
2868 else
2869 {
2870 const char *p = name;
2871
2872 name = CharNextExA (file_name_codepage, name, 0);
2873 memcpy (str, p, name - p);
2874 str += name - p;
2875 }
2876 }
2877 while ( *name );
2878
2879 *str++ = '\\';
2880 *str = 0;
2881 }
2882
2883 if (pPath)
2884 *pPath = name;
2885
2886 info = GetCachedVolumeInformation (rootname);
2887 if (info != NULL)
2888 {
2889 /* Set global referenced by other functions. */
2890 volume_info = *info;
2891 return TRUE;
2892 }
2893 return FALSE;
2894 }
2895
2896 /* Determine if volume is FAT format (ie. only supports short 8.3
2897 names); also set path pointer to start of pathname in name, if
2898 pPath is non-NULL. */
2899 static int
2900 is_fat_volume (const char * name, const char ** pPath)
2901 {
2902 if (get_volume_info (name, pPath))
2903 return (volume_info.maxcomp == 12);
2904 return FALSE;
2905 }
2906
2907 /* Map filename to a valid 8.3 name if necessary.
2908 The result is a pointer to a static buffer, so CAVEAT EMPTOR! */
2909 const char *
2910 map_w32_filename (const char * name, const char ** pPath)
2911 {
2912 static char shortname[MAX_PATH];
2913 char * str = shortname;
2914 char c;
2915 char * path;
2916 const char * save_name = name;
2917
2918 if (strlen (name) >= MAX_PATH)
2919 {
2920 /* Return a filename which will cause callers to fail. */
2921 strcpy (shortname, "?");
2922 return shortname;
2923 }
2924
2925 if (is_fat_volume (name, (const char **)&path)) /* truncate to 8.3 */
2926 {
2927 register int left = 8; /* maximum number of chars in part */
2928 register int extn = 0; /* extension added? */
2929 register int dots = 2; /* maximum number of dots allowed */
2930
2931 while (name < path)
2932 *str++ = *name++; /* skip past UNC header */
2933
2934 while ((c = *name++))
2935 {
2936 switch ( c )
2937 {
2938 case ':':
2939 case '\\':
2940 case '/':
2941 *str++ = (c == ':' ? ':' : '\\');
2942 extn = 0; /* reset extension flags */
2943 dots = 2; /* max 2 dots */
2944 left = 8; /* max length 8 for main part */
2945 break;
2946 case '.':
2947 if ( dots )
2948 {
2949 /* Convert path components of the form .xxx to _xxx,
2950 but leave . and .. as they are. This allows .emacs
2951 to be read as _emacs, for example. */
2952
2953 if (! *name ||
2954 *name == '.' ||
2955 IS_DIRECTORY_SEP (*name))
2956 {
2957 *str++ = '.';
2958 dots--;
2959 }
2960 else
2961 {
2962 *str++ = '_';
2963 left--;
2964 dots = 0;
2965 }
2966 }
2967 else if ( !extn )
2968 {
2969 *str++ = '.';
2970 extn = 1; /* we've got an extension */
2971 left = 3; /* 3 chars in extension */
2972 }
2973 else
2974 {
2975 /* any embedded dots after the first are converted to _ */
2976 *str++ = '_';
2977 }
2978 break;
2979 case '~':
2980 case '#': /* don't lose these, they're important */
2981 if ( ! left )
2982 str[-1] = c; /* replace last character of part */
2983 /* FALLTHRU */
2984 default:
2985 if ( left )
2986 {
2987 *str++ = tolower (c); /* map to lower case (looks nicer) */
2988 left--;
2989 dots = 0; /* started a path component */
2990 }
2991 break;
2992 }
2993 }
2994 *str = '\0';
2995 }
2996 else
2997 {
2998 strcpy (shortname, name);
2999 unixtodos_filename (shortname);
3000 }
3001
3002 if (pPath)
3003 *pPath = shortname + (path - save_name);
3004
3005 return shortname;
3006 }
3007
3008 static int
3009 is_exec (const char * name)
3010 {
3011 char * p = strrchr (name, '.');
3012 return
3013 (p != NULL
3014 && (xstrcasecmp (p, ".exe") == 0 ||
3015 xstrcasecmp (p, ".com") == 0 ||
3016 xstrcasecmp (p, ".bat") == 0 ||
3017 xstrcasecmp (p, ".cmd") == 0));
3018 }
3019
3020 /* Emulate the Unix directory procedures opendir, closedir,
3021 and readdir. We can't use the procedures supplied in sysdep.c,
3022 so we provide them here. */
3023
3024 struct dirent dir_static; /* simulated directory contents */
3025 static HANDLE dir_find_handle = INVALID_HANDLE_VALUE;
3026 static int dir_is_fat;
3027 static char dir_pathname[MAXPATHLEN+1];
3028 static WIN32_FIND_DATA dir_find_data;
3029
3030 /* Support shares on a network resource as subdirectories of a read-only
3031 root directory. */
3032 static HANDLE wnet_enum_handle = INVALID_HANDLE_VALUE;
3033 static HANDLE open_unc_volume (const char *);
3034 static char *read_unc_volume (HANDLE, char *, int);
3035 static void close_unc_volume (HANDLE);
3036
3037 DIR *
3038 opendir (const char *filename)
3039 {
3040 DIR *dirp;
3041
3042 /* Opening is done by FindFirstFile. However, a read is inherent to
3043 this operation, so we defer the open until read time. */
3044
3045 if (dir_find_handle != INVALID_HANDLE_VALUE)
3046 return NULL;
3047 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
3048 return NULL;
3049
3050 /* Note: We don't support traversal of UNC volumes via symlinks.
3051 Doing so would mean punishing 99.99% of use cases by resolving
3052 all the possible symlinks in FILENAME, recursively. */
3053 if (is_unc_volume (filename))
3054 {
3055 wnet_enum_handle = open_unc_volume (filename);
3056 if (wnet_enum_handle == INVALID_HANDLE_VALUE)
3057 return NULL;
3058 }
3059
3060 if (!(dirp = (DIR *) malloc (sizeof (DIR))))
3061 return NULL;
3062
3063 dirp->dd_fd = 0;
3064 dirp->dd_loc = 0;
3065 dirp->dd_size = 0;
3066
3067 strncpy (dir_pathname, map_w32_filename (filename, NULL), MAXPATHLEN);
3068 dir_pathname[MAXPATHLEN] = '\0';
3069 /* Note: We don't support symlinks to file names on FAT volumes.
3070 Doing so would mean punishing 99.99% of use cases by resolving
3071 all the possible symlinks in FILENAME, recursively. */
3072 dir_is_fat = is_fat_volume (filename, NULL);
3073
3074 return dirp;
3075 }
3076
3077 void
3078 closedir (DIR *dirp)
3079 {
3080 /* If we have a find-handle open, close it. */
3081 if (dir_find_handle != INVALID_HANDLE_VALUE)
3082 {
3083 FindClose (dir_find_handle);
3084 dir_find_handle = INVALID_HANDLE_VALUE;
3085 }
3086 else if (wnet_enum_handle != INVALID_HANDLE_VALUE)
3087 {
3088 close_unc_volume (wnet_enum_handle);
3089 wnet_enum_handle = INVALID_HANDLE_VALUE;
3090 }
3091 xfree ((char *) dirp);
3092 }
3093
3094 struct dirent *
3095 readdir (DIR *dirp)
3096 {
3097 int downcase = !NILP (Vw32_downcase_file_names);
3098
3099 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
3100 {
3101 if (!read_unc_volume (wnet_enum_handle,
3102 dir_find_data.cFileName,
3103 MAX_PATH))
3104 return NULL;
3105 }
3106 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
3107 else if (dir_find_handle == INVALID_HANDLE_VALUE)
3108 {
3109 char filename[MAXNAMLEN + 3];
3110 int ln;
3111 int dbcs_p = max_filename_mbslen () > 1;
3112
3113 strcpy (filename, dir_pathname);
3114 ln = strlen (filename) - 1;
3115 if (!dbcs_p)
3116 {
3117 if (!IS_DIRECTORY_SEP (filename[ln]))
3118 strcat (filename, "\\");
3119 }
3120 else
3121 {
3122 char *end = filename + ln + 1;
3123 char *last_char = CharPrevExA (file_name_codepage, filename, end, 0);
3124
3125 if (!IS_DIRECTORY_SEP (*last_char))
3126 strcat (filename, "\\");
3127 }
3128 strcat (filename, "*");
3129
3130 /* Note: No need to resolve symlinks in FILENAME, because
3131 FindFirst opens the directory that is the target of a
3132 symlink. */
3133 dir_find_handle = FindFirstFile (filename, &dir_find_data);
3134
3135 if (dir_find_handle == INVALID_HANDLE_VALUE)
3136 return NULL;
3137 }
3138 else
3139 {
3140 if (!FindNextFile (dir_find_handle, &dir_find_data))
3141 return NULL;
3142 }
3143
3144 /* Emacs never uses this value, so don't bother making it match
3145 value returned by stat(). */
3146 dir_static.d_ino = 1;
3147
3148 strcpy (dir_static.d_name, dir_find_data.cFileName);
3149
3150 /* If the file name in cFileName[] includes `?' characters, it means
3151 the original file name used characters that cannot be represented
3152 by the current ANSI codepage. To avoid total lossage, retrieve
3153 the short 8+3 alias of the long file name. */
3154 if (_mbspbrk (dir_static.d_name, "?"))
3155 {
3156 strcpy (dir_static.d_name, dir_find_data.cAlternateFileName);
3157 downcase = 1; /* 8+3 aliases are returned in all caps */
3158 }
3159 dir_static.d_namlen = strlen (dir_static.d_name);
3160 dir_static.d_reclen = sizeof (struct dirent) - MAXNAMLEN + 3 +
3161 dir_static.d_namlen - dir_static.d_namlen % 4;
3162
3163 /* If the file name in cFileName[] includes `?' characters, it means
3164 the original file name used characters that cannot be represented
3165 by the current ANSI codepage. To avoid total lossage, retrieve
3166 the short 8+3 alias of the long file name. */
3167 if (_mbspbrk (dir_find_data.cFileName, "?"))
3168 {
3169 strcpy (dir_static.d_name, dir_find_data.cAlternateFileName);
3170 /* 8+3 aliases are returned in all caps, which could break
3171 various alists that look at filenames' extensions. */
3172 downcase = 1;
3173 }
3174 else
3175 strcpy (dir_static.d_name, dir_find_data.cFileName);
3176 dir_static.d_namlen = strlen (dir_static.d_name);
3177 if (dir_is_fat)
3178 _mbslwr (dir_static.d_name);
3179 else if (downcase)
3180 {
3181 register char *p;
3182 int dbcs_p = max_filename_mbslen () > 1;
3183 for (p = dir_static.d_name; *p; )
3184 {
3185 if (*p >= 'a' && *p <= 'z')
3186 break;
3187 if (dbcs_p)
3188 p = CharNextExA (file_name_codepage, p, 0);
3189 else
3190 p++;
3191 }
3192 if (!*p)
3193 _mbslwr (dir_static.d_name);
3194 }
3195
3196 return &dir_static;
3197 }
3198
3199 static HANDLE
3200 open_unc_volume (const char *path)
3201 {
3202 NETRESOURCE nr;
3203 HANDLE henum;
3204 int result;
3205
3206 nr.dwScope = RESOURCE_GLOBALNET;
3207 nr.dwType = RESOURCETYPE_DISK;
3208 nr.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
3209 nr.dwUsage = RESOURCEUSAGE_CONTAINER;
3210 nr.lpLocalName = NULL;
3211 nr.lpRemoteName = (LPSTR)map_w32_filename (path, NULL);
3212 nr.lpComment = NULL;
3213 nr.lpProvider = NULL;
3214
3215 result = WNetOpenEnum (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
3216 RESOURCEUSAGE_CONNECTABLE, &nr, &henum);
3217
3218 if (result == NO_ERROR)
3219 return henum;
3220 else
3221 return INVALID_HANDLE_VALUE;
3222 }
3223
3224 static char *
3225 read_unc_volume (HANDLE henum, char *readbuf, int size)
3226 {
3227 DWORD count;
3228 int result;
3229 DWORD bufsize = 512;
3230 char *buffer;
3231 char *ptr;
3232 int dbcs_p = max_filename_mbslen () > 1;
3233
3234 count = 1;
3235 buffer = alloca (bufsize);
3236 result = WNetEnumResource (henum, &count, buffer, &bufsize);
3237 if (result != NO_ERROR)
3238 return NULL;
3239
3240 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
3241 ptr = ((LPNETRESOURCE) buffer)->lpRemoteName;
3242 ptr += 2;
3243 if (!dbcs_p)
3244 while (*ptr && !IS_DIRECTORY_SEP (*ptr)) ptr++;
3245 else
3246 {
3247 while (*ptr && !IS_DIRECTORY_SEP (*ptr))
3248 ptr = CharNextExA (file_name_codepage, ptr, 0);
3249 }
3250 ptr++;
3251
3252 strncpy (readbuf, ptr, size);
3253 return readbuf;
3254 }
3255
3256 static void
3257 close_unc_volume (HANDLE henum)
3258 {
3259 if (henum != INVALID_HANDLE_VALUE)
3260 WNetCloseEnum (henum);
3261 }
3262
3263 static DWORD
3264 unc_volume_file_attributes (const char *path)
3265 {
3266 HANDLE henum;
3267 DWORD attrs;
3268
3269 henum = open_unc_volume (path);
3270 if (henum == INVALID_HANDLE_VALUE)
3271 return -1;
3272
3273 attrs = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY;
3274
3275 close_unc_volume (henum);
3276
3277 return attrs;
3278 }
3279
3280 /* Ensure a network connection is authenticated. */
3281 static void
3282 logon_network_drive (const char *path)
3283 {
3284 NETRESOURCE resource;
3285 char share[MAX_PATH];
3286 int n_slashes;
3287 char drive[4];
3288 UINT drvtype;
3289 char *p;
3290 int dbcs_p;
3291
3292 if (IS_DIRECTORY_SEP (path[0]) && IS_DIRECTORY_SEP (path[1]))
3293 drvtype = DRIVE_REMOTE;
3294 else if (path[0] == '\0' || path[1] != ':')
3295 drvtype = GetDriveType (NULL);
3296 else
3297 {
3298 drive[0] = path[0];
3299 drive[1] = ':';
3300 drive[2] = '\\';
3301 drive[3] = '\0';
3302 drvtype = GetDriveType (drive);
3303 }
3304
3305 /* Only logon to networked drives. */
3306 if (drvtype != DRIVE_REMOTE)
3307 return;
3308
3309 n_slashes = 2;
3310 strncpy (share, path, MAX_PATH);
3311 /* Truncate to just server and share name. */
3312 dbcs_p = max_filename_mbslen () > 1;
3313 for (p = share + 2; *p && p < share + MAX_PATH; )
3314 {
3315 if (IS_DIRECTORY_SEP (*p) && ++n_slashes > 3)
3316 {
3317 *p = '\0';
3318 break;
3319 }
3320 if (dbcs_p)
3321 p = CharNextExA (file_name_codepage, p, 0);
3322 else
3323 p++;
3324 }
3325
3326 resource.dwType = RESOURCETYPE_DISK;
3327 resource.lpLocalName = NULL;
3328 resource.lpRemoteName = share;
3329 resource.lpProvider = NULL;
3330
3331 WNetAddConnection2 (&resource, NULL, NULL, CONNECT_INTERACTIVE);
3332 }
3333
3334 /* Emulate faccessat(2). */
3335 int
3336 faccessat (int dirfd, const char * path, int mode, int flags)
3337 {
3338 DWORD attributes;
3339
3340 if (dirfd != AT_FDCWD
3341 && !(IS_DIRECTORY_SEP (path[0])
3342 || IS_DEVICE_SEP (path[1])))
3343 {
3344 errno = EBADF;
3345 return -1;
3346 }
3347
3348 /* MSVCRT implementation of 'access' doesn't recognize D_OK, and its
3349 newer versions blow up when passed D_OK. */
3350 path = map_w32_filename (path, NULL);
3351 /* If the last element of PATH is a symlink, we need to resolve it
3352 to get the attributes of its target file. Note: any symlinks in
3353 PATH elements other than the last one are transparently resolved
3354 by GetFileAttributes below. */
3355 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0
3356 && (flags & AT_SYMLINK_NOFOLLOW) == 0)
3357 path = chase_symlinks (path);
3358
3359 if ((attributes = GetFileAttributes (path)) == -1)
3360 {
3361 DWORD w32err = GetLastError ();
3362
3363 switch (w32err)
3364 {
3365 case ERROR_INVALID_NAME:
3366 case ERROR_BAD_PATHNAME:
3367 if (is_unc_volume (path))
3368 {
3369 attributes = unc_volume_file_attributes (path);
3370 if (attributes == -1)
3371 {
3372 errno = EACCES;
3373 return -1;
3374 }
3375 break;
3376 }
3377 /* FALLTHROUGH */
3378 case ERROR_FILE_NOT_FOUND:
3379 case ERROR_BAD_NETPATH:
3380 errno = ENOENT;
3381 break;
3382 default:
3383 errno = EACCES;
3384 break;
3385 }
3386 return -1;
3387 }
3388 if ((mode & X_OK) != 0
3389 && !(is_exec (path) || (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0))
3390 {
3391 errno = EACCES;
3392 return -1;
3393 }
3394 if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0)
3395 {
3396 errno = EACCES;
3397 return -1;
3398 }
3399 if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
3400 {
3401 errno = EACCES;
3402 return -1;
3403 }
3404 return 0;
3405 }
3406
3407 /* Shadow some MSVC runtime functions to map requests for long filenames
3408 to reasonable short names if necessary. This was originally added to
3409 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
3410 long file names. */
3411
3412 int
3413 sys_chdir (const char * path)
3414 {
3415 /* FIXME: Temporary. Also, figure out what to do with
3416 map_w32_filename, as the original code did this:
3417 _chdir(map_w32_filename (path, NULL)). */
3418 if (w32_unicode_filenames)
3419 {
3420 wchar_t newdir[MAXPATHLEN];
3421
3422 if (filename_to_utf16 (path, newdir) == 0)
3423 return _wchdir (newdir);
3424 return -1;
3425 }
3426 else
3427 {
3428 char newdir[MAXPATHLEN];
3429
3430 if (filename_to_ansi (path, newdir) == 0)
3431 return _chdir (path);
3432 return -1;
3433 }
3434 }
3435
3436 int
3437 sys_chmod (const char * path, int mode)
3438 {
3439 path = chase_symlinks (map_w32_filename (path, NULL));
3440 return _chmod (path, mode);
3441 }
3442
3443 int
3444 sys_creat (const char * path, int mode)
3445 {
3446 return _creat (map_w32_filename (path, NULL), mode);
3447 }
3448
3449 FILE *
3450 sys_fopen (const char * path, const char * mode)
3451 {
3452 int fd;
3453 int oflag;
3454 const char * mode_save = mode;
3455
3456 /* Force all file handles to be non-inheritable. This is necessary to
3457 ensure child processes don't unwittingly inherit handles that might
3458 prevent future file access. */
3459
3460 if (mode[0] == 'r')
3461 oflag = O_RDONLY;
3462 else if (mode[0] == 'w' || mode[0] == 'a')
3463 oflag = O_WRONLY | O_CREAT | O_TRUNC;
3464 else
3465 return NULL;
3466
3467 /* Only do simplistic option parsing. */
3468 while (*++mode)
3469 if (mode[0] == '+')
3470 {
3471 oflag &= ~(O_RDONLY | O_WRONLY);
3472 oflag |= O_RDWR;
3473 }
3474 else if (mode[0] == 'b')
3475 {
3476 oflag &= ~O_TEXT;
3477 oflag |= O_BINARY;
3478 }
3479 else if (mode[0] == 't')
3480 {
3481 oflag &= ~O_BINARY;
3482 oflag |= O_TEXT;
3483 }
3484 else break;
3485
3486 fd = _open (map_w32_filename (path, NULL), oflag | _O_NOINHERIT, 0644);
3487 if (fd < 0)
3488 return NULL;
3489
3490 return _fdopen (fd, mode_save);
3491 }
3492
3493 /* This only works on NTFS volumes, but is useful to have. */
3494 int
3495 sys_link (const char * old, const char * new)
3496 {
3497 HANDLE fileh;
3498 int result = -1;
3499 char oldname[MAX_PATH], newname[MAX_PATH];
3500
3501 if (old == NULL || new == NULL)
3502 {
3503 errno = ENOENT;
3504 return -1;
3505 }
3506
3507 strcpy (oldname, map_w32_filename (old, NULL));
3508 strcpy (newname, map_w32_filename (new, NULL));
3509
3510 fileh = CreateFile (oldname, 0, 0, NULL, OPEN_EXISTING,
3511 FILE_FLAG_BACKUP_SEMANTICS, NULL);
3512 if (fileh != INVALID_HANDLE_VALUE)
3513 {
3514 int wlen;
3515
3516 /* Confusingly, the "alternate" stream name field does not apply
3517 when restoring a hard link, and instead contains the actual
3518 stream data for the link (ie. the name of the link to create).
3519 The WIN32_STREAM_ID structure before the cStreamName field is
3520 the stream header, which is then immediately followed by the
3521 stream data. */
3522
3523 struct {
3524 WIN32_STREAM_ID wid;
3525 WCHAR wbuffer[MAX_PATH]; /* extra space for link name */
3526 } data;
3527
3528 wlen = MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, newname, -1,
3529 data.wid.cStreamName, MAX_PATH);
3530 if (wlen > 0)
3531 {
3532 LPVOID context = NULL;
3533 DWORD wbytes = 0;
3534
3535 data.wid.dwStreamId = BACKUP_LINK;
3536 data.wid.dwStreamAttributes = 0;
3537 data.wid.Size.LowPart = wlen * sizeof (WCHAR);
3538 data.wid.Size.HighPart = 0;
3539 data.wid.dwStreamNameSize = 0;
3540
3541 if (BackupWrite (fileh, (LPBYTE)&data,
3542 offsetof (WIN32_STREAM_ID, cStreamName)
3543 + data.wid.Size.LowPart,
3544 &wbytes, FALSE, FALSE, &context)
3545 && BackupWrite (fileh, NULL, 0, &wbytes, TRUE, FALSE, &context))
3546 {
3547 /* succeeded */
3548 result = 0;
3549 }
3550 else
3551 {
3552 /* Should try mapping GetLastError to errno; for now just
3553 indicate a general error (eg. links not supported). */
3554 errno = EINVAL; // perhaps EMLINK?
3555 }
3556 }
3557
3558 CloseHandle (fileh);
3559 }
3560 else
3561 errno = ENOENT;
3562
3563 return result;
3564 }
3565
3566 int
3567 sys_mkdir (const char * path)
3568 {
3569 return _mkdir (map_w32_filename (path, NULL));
3570 }
3571
3572 int
3573 sys_open (const char * path, int oflag, int mode)
3574 {
3575 const char* mpath = map_w32_filename (path, NULL);
3576 int res = -1;
3577
3578 /* If possible, try to open file without _O_CREAT, to be able to
3579 write to existing hidden and system files. Force all file
3580 handles to be non-inheritable. */
3581 if ((oflag & (_O_CREAT | _O_EXCL)) != (_O_CREAT | _O_EXCL))
3582 res = _open (mpath, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
3583 if (res < 0)
3584 res = _open (mpath, oflag | _O_NOINHERIT, mode);
3585
3586 return res;
3587 }
3588
3589 /* Implementation of mkostemp for MS-Windows, to avoid race conditions
3590 when using mktemp.
3591
3592 Standard algorithm for generating a temporary file name seems to be
3593 use pid or tid with a letter on the front (in place of the 6 X's)
3594 and cycle through the letters to find a unique name. We extend
3595 that to allow any reasonable character as the first of the 6 X's,
3596 so that the number of simultaneously used temporary files will be
3597 greater. */
3598
3599 int
3600 mkostemp (char * template, int flags)
3601 {
3602 char * p;
3603 int i, fd = -1;
3604 unsigned uid = GetCurrentThreadId ();
3605 int save_errno = errno;
3606 static char first_char[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
3607
3608 errno = EINVAL;
3609 if (template == NULL)
3610 return -1;
3611
3612 p = template + strlen (template);
3613 i = 5;
3614 /* replace up to the last 5 X's with uid in decimal */
3615 while (--p >= template && p[0] == 'X' && --i >= 0)
3616 {
3617 p[0] = '0' + uid % 10;
3618 uid /= 10;
3619 }
3620
3621 if (i < 0 && p[0] == 'X')
3622 {
3623 i = 0;
3624 do
3625 {
3626 p[0] = first_char[i];
3627 if ((fd = sys_open (template,
3628 flags | _O_CREAT | _O_EXCL | _O_RDWR,
3629 S_IRUSR | S_IWUSR)) >= 0
3630 || errno != EEXIST)
3631 {
3632 if (fd >= 0)
3633 errno = save_errno;
3634 return fd;
3635 }
3636 }
3637 while (++i < sizeof (first_char));
3638 }
3639
3640 /* Template is badly formed or else we can't generate a unique name. */
3641 return -1;
3642 }
3643
3644 int
3645 fchmod (int fd, mode_t mode)
3646 {
3647 return 0;
3648 }
3649
3650 int
3651 sys_rename_replace (const char *oldname, const char *newname, BOOL force)
3652 {
3653 BOOL result;
3654 char temp[MAX_PATH];
3655 int newname_dev;
3656 int oldname_dev;
3657
3658 /* MoveFile on Windows 95 doesn't correctly change the short file name
3659 alias in a number of circumstances (it is not easy to predict when
3660 just by looking at oldname and newname, unfortunately). In these
3661 cases, renaming through a temporary name avoids the problem.
3662
3663 A second problem on Windows 95 is that renaming through a temp name when
3664 newname is uppercase fails (the final long name ends up in
3665 lowercase, although the short alias might be uppercase) UNLESS the
3666 long temp name is not 8.3.
3667
3668 So, on Windows 95 we always rename through a temp name, and we make sure
3669 the temp name has a long extension to ensure correct renaming. */
3670
3671 strcpy (temp, map_w32_filename (oldname, NULL));
3672
3673 /* volume_info is set indirectly by map_w32_filename. */
3674 oldname_dev = volume_info.serialnum;
3675
3676 if (os_subtype == OS_9X)
3677 {
3678 char * o;
3679 char * p;
3680 int i = 0;
3681
3682 oldname = map_w32_filename (oldname, NULL);
3683 if ((o = strrchr (oldname, '\\')))
3684 o++;
3685 else
3686 o = (char *) oldname;
3687
3688 if ((p = strrchr (temp, '\\')))
3689 p++;
3690 else
3691 p = temp;
3692
3693 do
3694 {
3695 /* Force temp name to require a manufactured 8.3 alias - this
3696 seems to make the second rename work properly. */
3697 sprintf (p, "_.%s.%u", o, i);
3698 i++;
3699 result = rename (oldname, temp);
3700 }
3701 /* This loop must surely terminate! */
3702 while (result < 0 && errno == EEXIST);
3703 if (result < 0)
3704 return -1;
3705 }
3706
3707 /* If FORCE, emulate Unix behavior - newname is deleted if it already exists
3708 (at least if it is a file; don't do this for directories).
3709
3710 Since we mustn't do this if we are just changing the case of the
3711 file name (we would end up deleting the file we are trying to
3712 rename!), we let rename detect if the destination file already
3713 exists - that way we avoid the possible pitfalls of trying to
3714 determine ourselves whether two names really refer to the same
3715 file, which is not always possible in the general case. (Consider
3716 all the permutations of shared or subst'd drives, etc.) */
3717
3718 newname = map_w32_filename (newname, NULL);
3719
3720 /* volume_info is set indirectly by map_w32_filename. */
3721 newname_dev = volume_info.serialnum;
3722
3723 result = rename (temp, newname);
3724
3725 if (result < 0 && force)
3726 {
3727 DWORD w32err = GetLastError ();
3728
3729 if (errno == EACCES
3730 && newname_dev != oldname_dev)
3731 {
3732 /* The implementation of `rename' on Windows does not return
3733 errno = EXDEV when you are moving a directory to a
3734 different storage device (ex. logical disk). It returns
3735 EACCES instead. So here we handle such situations and
3736 return EXDEV. */
3737 DWORD attributes;
3738
3739 if ((attributes = GetFileAttributes (temp)) != -1
3740 && (attributes & FILE_ATTRIBUTE_DIRECTORY))
3741 errno = EXDEV;
3742 }
3743 else if (errno == EEXIST)
3744 {
3745 if (_chmod (newname, 0666) != 0)
3746 return result;
3747 if (_unlink (newname) != 0)
3748 return result;
3749 result = rename (temp, newname);
3750 }
3751 else if (w32err == ERROR_PRIVILEGE_NOT_HELD
3752 && is_symlink (temp))
3753 {
3754 /* This is Windows prohibiting the user from creating a
3755 symlink in another place, since that requires
3756 privileges. */
3757 errno = EPERM;
3758 }
3759 }
3760
3761 return result;
3762 }
3763
3764 int
3765 sys_rename (char const *old, char const *new)
3766 {
3767 return sys_rename_replace (old, new, TRUE);
3768 }
3769
3770 int
3771 sys_rmdir (const char * path)
3772 {
3773 return _rmdir (map_w32_filename (path, NULL));
3774 }
3775
3776 int
3777 sys_unlink (const char * path)
3778 {
3779 path = map_w32_filename (path, NULL);
3780
3781 /* On Unix, unlink works without write permission. */
3782 _chmod (path, 0666);
3783 return _unlink (path);
3784 }
3785
3786 static FILETIME utc_base_ft;
3787 static ULONGLONG utc_base; /* In 100ns units */
3788 static int init = 0;
3789
3790 #define FILETIME_TO_U64(result, ft) \
3791 do { \
3792 ULARGE_INTEGER uiTemp; \
3793 uiTemp.LowPart = (ft).dwLowDateTime; \
3794 uiTemp.HighPart = (ft).dwHighDateTime; \
3795 result = uiTemp.QuadPart; \
3796 } while (0)
3797
3798 static void
3799 initialize_utc_base (void)
3800 {
3801 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
3802 SYSTEMTIME st;
3803
3804 st.wYear = 1970;
3805 st.wMonth = 1;
3806 st.wDay = 1;
3807 st.wHour = 0;
3808 st.wMinute = 0;
3809 st.wSecond = 0;
3810 st.wMilliseconds = 0;
3811
3812 SystemTimeToFileTime (&st, &utc_base_ft);
3813 FILETIME_TO_U64 (utc_base, utc_base_ft);
3814 }
3815
3816 static time_t
3817 convert_time (FILETIME ft)
3818 {
3819 ULONGLONG tmp;
3820
3821 if (!init)
3822 {
3823 initialize_utc_base ();
3824 init = 1;
3825 }
3826
3827 if (CompareFileTime (&ft, &utc_base_ft) < 0)
3828 return 0;
3829
3830 FILETIME_TO_U64 (tmp, ft);
3831 return (time_t) ((tmp - utc_base) / 10000000L);
3832 }
3833
3834 static void
3835 convert_from_time_t (time_t time, FILETIME * pft)
3836 {
3837 ULARGE_INTEGER tmp;
3838
3839 if (!init)
3840 {
3841 initialize_utc_base ();
3842 init = 1;
3843 }
3844
3845 /* time in 100ns units since 1-Jan-1601 */
3846 tmp.QuadPart = (ULONGLONG) time * 10000000L + utc_base;
3847 pft->dwHighDateTime = tmp.HighPart;
3848 pft->dwLowDateTime = tmp.LowPart;
3849 }
3850
3851 #if 0
3852 /* No reason to keep this; faking inode values either by hashing or even
3853 using the file index from GetInformationByHandle, is not perfect and
3854 so by default Emacs doesn't use the inode values on Windows.
3855 Instead, we now determine file-truename correctly (except for
3856 possible drive aliasing etc). */
3857
3858 /* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
3859 static unsigned
3860 hashval (const unsigned char * str)
3861 {
3862 unsigned h = 0;
3863 while (*str)
3864 {
3865 h = (h << 4) + *str++;
3866 h ^= (h >> 28);
3867 }
3868 return h;
3869 }
3870
3871 /* Return the hash value of the canonical pathname, excluding the
3872 drive/UNC header, to get a hopefully unique inode number. */
3873 static DWORD
3874 generate_inode_val (const char * name)
3875 {
3876 char fullname[ MAX_PATH ];
3877 char * p;
3878 unsigned hash;
3879
3880 /* Get the truly canonical filename, if it exists. (Note: this
3881 doesn't resolve aliasing due to subst commands, or recognize hard
3882 links. */
3883 if (!w32_get_long_filename ((char *)name, fullname, MAX_PATH))
3884 emacs_abort ();
3885
3886 parse_root (fullname, &p);
3887 /* Normal W32 filesystems are still case insensitive. */
3888 _strlwr (p);
3889 return hashval (p);
3890 }
3891
3892 #endif
3893
3894 static PSECURITY_DESCRIPTOR
3895 get_file_security_desc_by_handle (HANDLE h)
3896 {
3897 PSECURITY_DESCRIPTOR psd = NULL;
3898 DWORD err;
3899 SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION
3900 | GROUP_SECURITY_INFORMATION /* | DACL_SECURITY_INFORMATION */ ;
3901
3902 err = get_security_info (h, SE_FILE_OBJECT, si,
3903 NULL, NULL, NULL, NULL, &psd);
3904 if (err != ERROR_SUCCESS)
3905 return NULL;
3906
3907 return psd;
3908 }
3909
3910 static PSECURITY_DESCRIPTOR
3911 get_file_security_desc_by_name (const char *fname)
3912 {
3913 PSECURITY_DESCRIPTOR psd = NULL;
3914 DWORD sd_len, err;
3915 SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION
3916 | GROUP_SECURITY_INFORMATION /* | DACL_SECURITY_INFORMATION */ ;
3917
3918 if (!get_file_security (fname, si, psd, 0, &sd_len))
3919 {
3920 err = GetLastError ();
3921 if (err != ERROR_INSUFFICIENT_BUFFER)
3922 return NULL;
3923 }
3924
3925 psd = xmalloc (sd_len);
3926 if (!get_file_security (fname, si, psd, sd_len, &sd_len))
3927 {
3928 xfree (psd);
3929 return NULL;
3930 }
3931
3932 return psd;
3933 }
3934
3935 static DWORD
3936 get_rid (PSID sid)
3937 {
3938 unsigned n_subauthorities;
3939
3940 /* Use the last sub-authority value of the RID, the relative
3941 portion of the SID, as user/group ID. */
3942 n_subauthorities = *get_sid_sub_authority_count (sid);
3943 if (n_subauthorities < 1)
3944 return 0; /* the "World" RID */
3945 return *get_sid_sub_authority (sid, n_subauthorities - 1);
3946 }
3947
3948 /* Caching SID and account values for faster lokup. */
3949
3950 struct w32_id {
3951 unsigned rid;
3952 struct w32_id *next;
3953 char name[GNLEN+1];
3954 unsigned char sid[FLEXIBLE_ARRAY_MEMBER];
3955 };
3956
3957 static struct w32_id *w32_idlist;
3958
3959 static int
3960 w32_cached_id (PSID sid, unsigned *id, char *name)
3961 {
3962 struct w32_id *tail, *found;
3963
3964 for (found = NULL, tail = w32_idlist; tail; tail = tail->next)
3965 {
3966 if (equal_sid ((PSID)tail->sid, sid))
3967 {
3968 found = tail;
3969 break;
3970 }
3971 }
3972 if (found)
3973 {
3974 *id = found->rid;
3975 strcpy (name, found->name);
3976 return 1;
3977 }
3978 else
3979 return 0;
3980 }
3981
3982 static void
3983 w32_add_to_cache (PSID sid, unsigned id, char *name)
3984 {
3985 DWORD sid_len;
3986 struct w32_id *new_entry;
3987
3988 /* We don't want to leave behind stale cache from when Emacs was
3989 dumped. */
3990 if (initialized)
3991 {
3992 sid_len = get_length_sid (sid);
3993 new_entry = xmalloc (offsetof (struct w32_id, sid) + sid_len);
3994 if (new_entry)
3995 {
3996 new_entry->rid = id;
3997 strcpy (new_entry->name, name);
3998 copy_sid (sid_len, (PSID)new_entry->sid, sid);
3999 new_entry->next = w32_idlist;
4000 w32_idlist = new_entry;
4001 }
4002 }
4003 }
4004
4005 #define UID 1
4006 #define GID 2
4007
4008 static int
4009 get_name_and_id (PSECURITY_DESCRIPTOR psd, unsigned *id, char *nm, int what)
4010 {
4011 PSID sid = NULL;
4012 BOOL dflt;
4013 SID_NAME_USE ignore;
4014 char name[UNLEN+1];
4015 DWORD name_len = sizeof (name);
4016 char domain[1024];
4017 DWORD domain_len = sizeof (domain);
4018 int use_dflt = 0;
4019 int result;
4020
4021 if (what == UID)
4022 result = get_security_descriptor_owner (psd, &sid, &dflt);
4023 else if (what == GID)
4024 result = get_security_descriptor_group (psd, &sid, &dflt);
4025 else
4026 result = 0;
4027
4028 if (!result || !is_valid_sid (sid))
4029 use_dflt = 1;
4030 else if (!w32_cached_id (sid, id, nm))
4031 {
4032 if (!lookup_account_sid (NULL, sid, name, &name_len,
4033 domain, &domain_len, &ignore)
4034 || name_len > UNLEN+1)
4035 use_dflt = 1;
4036 else
4037 {
4038 *id = get_rid (sid);
4039 strcpy (nm, name);
4040 w32_add_to_cache (sid, *id, name);
4041 }
4042 }
4043 return use_dflt;
4044 }
4045
4046 static void
4047 get_file_owner_and_group (PSECURITY_DESCRIPTOR psd, struct stat *st)
4048 {
4049 int dflt_usr = 0, dflt_grp = 0;
4050
4051 if (!psd)
4052 {
4053 dflt_usr = 1;
4054 dflt_grp = 1;
4055 }
4056 else
4057 {
4058 if (get_name_and_id (psd, &st->st_uid, st->st_uname, UID))
4059 dflt_usr = 1;
4060 if (get_name_and_id (psd, &st->st_gid, st->st_gname, GID))
4061 dflt_grp = 1;
4062 }
4063 /* Consider files to belong to current user/group, if we cannot get
4064 more accurate information. */
4065 if (dflt_usr)
4066 {
4067 st->st_uid = dflt_passwd.pw_uid;
4068 strcpy (st->st_uname, dflt_passwd.pw_name);
4069 }
4070 if (dflt_grp)
4071 {
4072 st->st_gid = dflt_passwd.pw_gid;
4073 strcpy (st->st_gname, dflt_group.gr_name);
4074 }
4075 }
4076
4077 /* Return non-zero if NAME is a potentially slow filesystem. */
4078 int
4079 is_slow_fs (const char *name)
4080 {
4081 char drive_root[4];
4082 UINT devtype;
4083
4084 if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
4085 devtype = DRIVE_REMOTE; /* assume UNC name is remote */
4086 else if (!(strlen (name) >= 2 && IS_DEVICE_SEP (name[1])))
4087 devtype = GetDriveType (NULL); /* use root of current drive */
4088 else
4089 {
4090 /* GetDriveType needs the root directory of the drive. */
4091 strncpy (drive_root, name, 2);
4092 drive_root[2] = '\\';
4093 drive_root[3] = '\0';
4094 devtype = GetDriveType (drive_root);
4095 }
4096 return !(devtype == DRIVE_FIXED || devtype == DRIVE_RAMDISK);
4097 }
4098
4099 /* If this is non-zero, the caller wants accurate information about
4100 file's owner and group, which could be expensive to get. */
4101 int w32_stat_get_owner_group;
4102
4103 /* MSVC stat function can't cope with UNC names and has other bugs, so
4104 replace it with our own. This also allows us to calculate consistent
4105 inode values and owner/group without hacks in the main Emacs code. */
4106
4107 static int
4108 stat_worker (const char * path, struct stat * buf, int follow_symlinks)
4109 {
4110 char *name, *save_name, *r;
4111 WIN32_FIND_DATA wfd;
4112 HANDLE fh;
4113 unsigned __int64 fake_inode = 0;
4114 int permission;
4115 int len;
4116 int rootdir = FALSE;
4117 PSECURITY_DESCRIPTOR psd = NULL;
4118 int is_a_symlink = 0;
4119 DWORD file_flags = FILE_FLAG_BACKUP_SEMANTICS;
4120 DWORD access_rights = 0;
4121 DWORD fattrs = 0, serialnum = 0, fs_high = 0, fs_low = 0, nlinks = 1;
4122 FILETIME ctime, atime, wtime;
4123 int dbcs_p;
4124
4125 if (path == NULL || buf == NULL)
4126 {
4127 errno = EFAULT;
4128 return -1;
4129 }
4130
4131 save_name = name = (char *) map_w32_filename (path, &path);
4132 /* Must be valid filename, no wild cards or other invalid
4133 characters. We use _mbspbrk to support multibyte strings that
4134 might look to strpbrk as if they included literal *, ?, and other
4135 characters mentioned below that are disallowed by Windows
4136 filesystems. */
4137 if (_mbspbrk (name, "*?|<>\""))
4138 {
4139 errno = ENOENT;
4140 return -1;
4141 }
4142
4143 /* Remove trailing directory separator, unless name is the root
4144 directory of a drive or UNC volume in which case ensure there
4145 is a trailing separator. */
4146 len = strlen (name);
4147 name = strcpy (alloca (len + 2), name);
4148
4149 /* Avoid a somewhat costly call to is_symlink if the filesystem
4150 doesn't support symlinks. */
4151 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
4152 is_a_symlink = is_symlink (name);
4153
4154 /* Plan A: Open the file and get all the necessary information via
4155 the resulting handle. This solves several issues in one blow:
4156
4157 . retrieves attributes for the target of a symlink, if needed
4158 . gets attributes of root directories and symlinks pointing to
4159 root directories, thus avoiding the need for special-casing
4160 these and detecting them by examining the file-name format
4161 . retrieves more accurate attributes (e.g., non-zero size for
4162 some directories, esp. directories that are junction points)
4163 . correctly resolves "c:/..", "/.." and similar file names
4164 . avoids run-time penalties for 99% of use cases
4165
4166 Plan A is always tried first, unless the user asked not to (but
4167 if the file is a symlink and we need to follow links, we try Plan
4168 A even if the user asked not to).
4169
4170 If Plan A fails, we go to Plan B (below), where various
4171 potentially expensive techniques must be used to handle "special"
4172 files such as UNC volumes etc. */
4173 if (!(NILP (Vw32_get_true_file_attributes)
4174 || (EQ (Vw32_get_true_file_attributes, Qlocal) && is_slow_fs (name)))
4175 /* Following symlinks requires getting the info by handle. */
4176 || (is_a_symlink && follow_symlinks))
4177 {
4178 BY_HANDLE_FILE_INFORMATION info;
4179
4180 if (is_a_symlink && !follow_symlinks)
4181 file_flags |= FILE_FLAG_OPEN_REPARSE_POINT;
4182 /* READ_CONTROL access rights are required to get security info
4183 by handle. But if the OS doesn't support security in the
4184 first place, we don't need to try. */
4185 if (is_windows_9x () != TRUE)
4186 access_rights |= READ_CONTROL;
4187
4188 fh = CreateFile (name, access_rights, 0, NULL, OPEN_EXISTING,
4189 file_flags, NULL);
4190 /* If CreateFile fails with READ_CONTROL, try again with zero as
4191 access rights. */
4192 if (fh == INVALID_HANDLE_VALUE && access_rights)
4193 fh = CreateFile (name, 0, 0, NULL, OPEN_EXISTING,
4194 file_flags, NULL);
4195 if (fh == INVALID_HANDLE_VALUE)
4196 goto no_true_file_attributes;
4197
4198 /* This is more accurate in terms of getting the correct number
4199 of links, but is quite slow (it is noticeable when Emacs is
4200 making a list of file name completions). */
4201 if (GetFileInformationByHandle (fh, &info))
4202 {
4203 nlinks = info.nNumberOfLinks;
4204 /* Might as well use file index to fake inode values, but this
4205 is not guaranteed to be unique unless we keep a handle open
4206 all the time (even then there are situations where it is
4207 not unique). Reputedly, there are at most 48 bits of info
4208 (on NTFS, presumably less on FAT). */
4209 fake_inode = info.nFileIndexHigh;
4210 fake_inode <<= 32;
4211 fake_inode += info.nFileIndexLow;
4212 serialnum = info.dwVolumeSerialNumber;
4213 fs_high = info.nFileSizeHigh;
4214 fs_low = info.nFileSizeLow;
4215 ctime = info.ftCreationTime;
4216 atime = info.ftLastAccessTime;
4217 wtime = info.ftLastWriteTime;
4218 fattrs = info.dwFileAttributes;
4219 }
4220 else
4221 {
4222 /* We don't go to Plan B here, because it's not clear that
4223 it's a good idea. The only known use case where
4224 CreateFile succeeds, but GetFileInformationByHandle fails
4225 (with ERROR_INVALID_FUNCTION) is for character devices
4226 such as NUL, PRN, etc. For these, switching to Plan B is
4227 a net loss, because we lose the character device
4228 attribute returned by GetFileType below (FindFirstFile
4229 doesn't set that bit in the attributes), and the other
4230 fields don't make sense for character devices anyway.
4231 Emacs doesn't really care for non-file entities in the
4232 context of l?stat, so neither do we. */
4233
4234 /* w32err is assigned so one could put a breakpoint here and
4235 examine its value, when GetFileInformationByHandle
4236 fails. */
4237 DWORD w32err = GetLastError ();
4238
4239 switch (w32err)
4240 {
4241 case ERROR_FILE_NOT_FOUND: /* can this ever happen? */
4242 errno = ENOENT;
4243 return -1;
4244 }
4245 }
4246
4247 /* Test for a symlink before testing for a directory, since
4248 symlinks to directories have the directory bit set, but we
4249 don't want them to appear as directories. */
4250 if (is_a_symlink && !follow_symlinks)
4251 buf->st_mode = S_IFLNK;
4252 else if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
4253 buf->st_mode = S_IFDIR;
4254 else
4255 {
4256 DWORD ftype = GetFileType (fh);
4257
4258 switch (ftype)
4259 {
4260 case FILE_TYPE_DISK:
4261 buf->st_mode = S_IFREG;
4262 break;
4263 case FILE_TYPE_PIPE:
4264 buf->st_mode = S_IFIFO;
4265 break;
4266 case FILE_TYPE_CHAR:
4267 case FILE_TYPE_UNKNOWN:
4268 default:
4269 buf->st_mode = S_IFCHR;
4270 }
4271 }
4272 /* We produce the fallback owner and group data, based on the
4273 current user that runs Emacs, in the following cases:
4274
4275 . caller didn't request owner and group info
4276 . this is Windows 9X
4277 . getting security by handle failed, and we need to produce
4278 information for the target of a symlink (this is better
4279 than producing a potentially misleading info about the
4280 symlink itself)
4281
4282 If getting security by handle fails, and we don't need to
4283 resolve symlinks, we try getting security by name. */
4284 if (!w32_stat_get_owner_group || is_windows_9x () == TRUE)
4285 get_file_owner_and_group (NULL, buf);
4286 else
4287 {
4288 psd = get_file_security_desc_by_handle (fh);
4289 if (psd)
4290 {
4291 get_file_owner_and_group (psd, buf);
4292 LocalFree (psd);
4293 }
4294 else if (!(is_a_symlink && follow_symlinks))
4295 {
4296 psd = get_file_security_desc_by_name (name);
4297 get_file_owner_and_group (psd, buf);
4298 xfree (psd);
4299 }
4300 else
4301 get_file_owner_and_group (NULL, buf);
4302 }
4303 CloseHandle (fh);
4304 }
4305 else
4306 {
4307 no_true_file_attributes:
4308 /* Plan B: Either getting a handle on the file failed, or the
4309 caller explicitly asked us to not bother making this
4310 information more accurate.
4311
4312 Implementation note: In Plan B, we never bother to resolve
4313 symlinks, even if we got here because we tried Plan A and
4314 failed. That's because, even if the caller asked for extra
4315 precision by setting Vw32_get_true_file_attributes to t,
4316 resolving symlinks requires acquiring a file handle to the
4317 symlink, which we already know will fail. And if the user
4318 did not ask for extra precision, resolving symlinks will fly
4319 in the face of that request, since the user then wants the
4320 lightweight version of the code. */
4321 dbcs_p = max_filename_mbslen () > 1;
4322 rootdir = (path >= save_name + len - 1
4323 && (IS_DIRECTORY_SEP (*path) || *path == 0));
4324
4325 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
4326 r = IS_DEVICE_SEP (name[1]) ? &name[2] : name;
4327 if (IS_DIRECTORY_SEP (r[0])
4328 && r[1] == '.' && r[2] == '.' && r[3] == '\0')
4329 r[1] = r[2] = '\0';
4330
4331 /* Note: If NAME is a symlink to the root of a UNC volume
4332 (i.e. "\\SERVER"), we will not detect that here, and we will
4333 return data about the symlink as result of FindFirst below.
4334 This is unfortunate, but that marginal use case does not
4335 justify a call to chase_symlinks which would impose a penalty
4336 on all the other use cases. (We get here for symlinks to
4337 roots of UNC volumes because CreateFile above fails for them,
4338 unlike with symlinks to root directories X:\ of drives.) */
4339 if (is_unc_volume (name))
4340 {
4341 fattrs = unc_volume_file_attributes (name);
4342 if (fattrs == -1)
4343 return -1;
4344
4345 ctime = atime = wtime = utc_base_ft;
4346 }
4347 else if (rootdir)
4348 {
4349 if (!dbcs_p)
4350 {
4351 if (!IS_DIRECTORY_SEP (name[len-1]))
4352 strcat (name, "\\");
4353 }
4354 else
4355 {
4356 char *end = name + len;
4357 char *n = CharPrevExA (file_name_codepage, name, end, 0);
4358
4359 if (!IS_DIRECTORY_SEP (*n))
4360 strcat (name, "\\");
4361 }
4362 if (GetDriveType (name) < 2)
4363 {
4364 errno = ENOENT;
4365 return -1;
4366 }
4367
4368 fattrs = FILE_ATTRIBUTE_DIRECTORY;
4369 ctime = atime = wtime = utc_base_ft;
4370 }
4371 else
4372 {
4373 if (!dbcs_p)
4374 {
4375 if (IS_DIRECTORY_SEP (name[len-1]))
4376 name[len - 1] = 0;
4377 }
4378 else
4379 {
4380 char *end = name + len;
4381 char *n = CharPrevExA (file_name_codepage, name, end, 0);
4382
4383 if (IS_DIRECTORY_SEP (*n))
4384 *n = 0;
4385 }
4386
4387 /* (This is hacky, but helps when doing file completions on
4388 network drives.) Optimize by using information available from
4389 active readdir if possible. */
4390 len = strlen (dir_pathname);
4391 if (!dbcs_p)
4392 {
4393 if (IS_DIRECTORY_SEP (dir_pathname[len-1]))
4394 len--;
4395 }
4396 else
4397 {
4398 char *end = dir_pathname + len;
4399 char *n = CharPrevExA (file_name_codepage, dir_pathname, end, 0);
4400
4401 if (IS_DIRECTORY_SEP (*n))
4402 len--;
4403 }
4404 if (dir_find_handle != INVALID_HANDLE_VALUE
4405 && !(is_a_symlink && follow_symlinks)
4406 && strnicmp (save_name, dir_pathname, len) == 0
4407 && IS_DIRECTORY_SEP (name[len])
4408 && xstrcasecmp (name + len + 1, dir_static.d_name) == 0)
4409 {
4410 /* This was the last entry returned by readdir. */
4411 wfd = dir_find_data;
4412 }
4413 else
4414 {
4415 logon_network_drive (name);
4416
4417 fh = FindFirstFile (name, &wfd);
4418 if (fh == INVALID_HANDLE_VALUE)
4419 {
4420 errno = ENOENT;
4421 return -1;
4422 }
4423 FindClose (fh);
4424 }
4425 /* Note: if NAME is a symlink, the information we get from
4426 FindFirstFile is for the symlink, not its target. */
4427 fattrs = wfd.dwFileAttributes;
4428 ctime = wfd.ftCreationTime;
4429 atime = wfd.ftLastAccessTime;
4430 wtime = wfd.ftLastWriteTime;
4431 fs_high = wfd.nFileSizeHigh;
4432 fs_low = wfd.nFileSizeLow;
4433 fake_inode = 0;
4434 nlinks = 1;
4435 serialnum = volume_info.serialnum;
4436 }
4437 if (is_a_symlink && !follow_symlinks)
4438 buf->st_mode = S_IFLNK;
4439 else if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
4440 buf->st_mode = S_IFDIR;
4441 else
4442 buf->st_mode = S_IFREG;
4443
4444 get_file_owner_and_group (NULL, buf);
4445 }
4446
4447 #if 0
4448 /* Not sure if there is any point in this. */
4449 if (!NILP (Vw32_generate_fake_inodes))
4450 fake_inode = generate_inode_val (name);
4451 else if (fake_inode == 0)
4452 {
4453 /* For want of something better, try to make everything unique. */
4454 static DWORD gen_num = 0;
4455 fake_inode = ++gen_num;
4456 }
4457 #endif
4458
4459 buf->st_ino = fake_inode;
4460
4461 buf->st_dev = serialnum;
4462 buf->st_rdev = serialnum;
4463
4464 buf->st_size = fs_high;
4465 buf->st_size <<= 32;
4466 buf->st_size += fs_low;
4467 buf->st_nlink = nlinks;
4468
4469 /* Convert timestamps to Unix format. */
4470 buf->st_mtime = convert_time (wtime);
4471 buf->st_atime = convert_time (atime);
4472 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
4473 buf->st_ctime = convert_time (ctime);
4474 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
4475
4476 /* determine rwx permissions */
4477 if (is_a_symlink && !follow_symlinks)
4478 permission = S_IREAD | S_IWRITE | S_IEXEC; /* Posix expectations */
4479 else
4480 {
4481 if (fattrs & FILE_ATTRIBUTE_READONLY)
4482 permission = S_IREAD;
4483 else
4484 permission = S_IREAD | S_IWRITE;
4485
4486 if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
4487 permission |= S_IEXEC;
4488 else if (is_exec (name))
4489 permission |= S_IEXEC;
4490 }
4491
4492 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
4493
4494 return 0;
4495 }
4496
4497 int
4498 stat (const char * path, struct stat * buf)
4499 {
4500 return stat_worker (path, buf, 1);
4501 }
4502
4503 int
4504 lstat (const char * path, struct stat * buf)
4505 {
4506 return stat_worker (path, buf, 0);
4507 }
4508
4509 int
4510 fstatat (int fd, char const *name, struct stat *st, int flags)
4511 {
4512 /* Rely on a hack: an open directory is modeled as file descriptor 0.
4513 This is good enough for the current usage in Emacs, but is fragile.
4514
4515 FIXME: Add proper support for fdopendir, fstatat, readlinkat.
4516 Gnulib does this and can serve as a model. */
4517 char fullname[MAX_PATH];
4518
4519 if (fd != AT_FDCWD)
4520 {
4521 if (_snprintf (fullname, sizeof fullname, "%s/%s", dir_pathname, name)
4522 < 0)
4523 {
4524 errno = ENAMETOOLONG;
4525 return -1;
4526 }
4527 name = fullname;
4528 }
4529
4530 return stat_worker (name, st, ! (flags & AT_SYMLINK_NOFOLLOW));
4531 }
4532
4533 /* Provide fstat and utime as well as stat for consistent handling of
4534 file timestamps. */
4535 int
4536 fstat (int desc, struct stat * buf)
4537 {
4538 HANDLE fh = (HANDLE) _get_osfhandle (desc);
4539 BY_HANDLE_FILE_INFORMATION info;
4540 unsigned __int64 fake_inode;
4541 int permission;
4542
4543 switch (GetFileType (fh) & ~FILE_TYPE_REMOTE)
4544 {
4545 case FILE_TYPE_DISK:
4546 buf->st_mode = S_IFREG;
4547 if (!GetFileInformationByHandle (fh, &info))
4548 {
4549 errno = EACCES;
4550 return -1;
4551 }
4552 break;
4553 case FILE_TYPE_PIPE:
4554 buf->st_mode = S_IFIFO;
4555 goto non_disk;
4556 case FILE_TYPE_CHAR:
4557 case FILE_TYPE_UNKNOWN:
4558 default:
4559 buf->st_mode = S_IFCHR;
4560 non_disk:
4561 memset (&info, 0, sizeof (info));
4562 info.dwFileAttributes = 0;
4563 info.ftCreationTime = utc_base_ft;
4564 info.ftLastAccessTime = utc_base_ft;
4565 info.ftLastWriteTime = utc_base_ft;
4566 }
4567
4568 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
4569 buf->st_mode = S_IFDIR;
4570
4571 buf->st_nlink = info.nNumberOfLinks;
4572 /* Might as well use file index to fake inode values, but this
4573 is not guaranteed to be unique unless we keep a handle open
4574 all the time (even then there are situations where it is
4575 not unique). Reputedly, there are at most 48 bits of info
4576 (on NTFS, presumably less on FAT). */
4577 fake_inode = info.nFileIndexHigh;
4578 fake_inode <<= 32;
4579 fake_inode += info.nFileIndexLow;
4580
4581 /* MSVC defines _ino_t to be short; other libc's might not. */
4582 if (sizeof (buf->st_ino) == 2)
4583 buf->st_ino = fake_inode ^ (fake_inode >> 16);
4584 else
4585 buf->st_ino = fake_inode;
4586
4587 /* If the caller so requested, get the true file owner and group.
4588 Otherwise, consider the file to belong to the current user. */
4589 if (!w32_stat_get_owner_group || is_windows_9x () == TRUE)
4590 get_file_owner_and_group (NULL, buf);
4591 else
4592 {
4593 PSECURITY_DESCRIPTOR psd = NULL;
4594
4595 psd = get_file_security_desc_by_handle (fh);
4596 if (psd)
4597 {
4598 get_file_owner_and_group (psd, buf);
4599 LocalFree (psd);
4600 }
4601 else
4602 get_file_owner_and_group (NULL, buf);
4603 }
4604
4605 buf->st_dev = info.dwVolumeSerialNumber;
4606 buf->st_rdev = info.dwVolumeSerialNumber;
4607
4608 buf->st_size = info.nFileSizeHigh;
4609 buf->st_size <<= 32;
4610 buf->st_size += info.nFileSizeLow;
4611
4612 /* Convert timestamps to Unix format. */
4613 buf->st_mtime = convert_time (info.ftLastWriteTime);
4614 buf->st_atime = convert_time (info.ftLastAccessTime);
4615 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
4616 buf->st_ctime = convert_time (info.ftCreationTime);
4617 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
4618
4619 /* determine rwx permissions */
4620 if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
4621 permission = S_IREAD;
4622 else
4623 permission = S_IREAD | S_IWRITE;
4624
4625 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
4626 permission |= S_IEXEC;
4627 else
4628 {
4629 #if 0 /* no way of knowing the filename */
4630 char * p = strrchr (name, '.');
4631 if (p != NULL &&
4632 (xstrcasecmp (p, ".exe") == 0 ||
4633 xstrcasecmp (p, ".com") == 0 ||
4634 xstrcasecmp (p, ".bat") == 0 ||
4635 xstrcasecmp (p, ".cmd") == 0))
4636 permission |= S_IEXEC;
4637 #endif
4638 }
4639
4640 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
4641
4642 return 0;
4643 }
4644
4645 /* A version of 'utime' which handles directories as well as
4646 files. */
4647
4648 int
4649 utime (const char *name, struct utimbuf *times)
4650 {
4651 struct utimbuf deftime;
4652 HANDLE fh;
4653 FILETIME mtime;
4654 FILETIME atime;
4655
4656 if (times == NULL)
4657 {
4658 deftime.modtime = deftime.actime = time (NULL);
4659 times = &deftime;
4660 }
4661
4662 /* Need write access to set times. */
4663 fh = CreateFile (name, FILE_WRITE_ATTRIBUTES,
4664 /* If NAME specifies a directory, FILE_SHARE_DELETE
4665 allows other processes to delete files inside it,
4666 while we have the directory open. */
4667 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
4668 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
4669 if (fh != INVALID_HANDLE_VALUE)
4670 {
4671 convert_from_time_t (times->actime, &atime);
4672 convert_from_time_t (times->modtime, &mtime);
4673 if (!SetFileTime (fh, NULL, &atime, &mtime))
4674 {
4675 CloseHandle (fh);
4676 errno = EACCES;
4677 return -1;
4678 }
4679 CloseHandle (fh);
4680 }
4681 else
4682 {
4683 errno = EINVAL;
4684 return -1;
4685 }
4686 return 0;
4687 }
4688
4689 \f
4690 /* Symlink-related functions. */
4691 #ifndef SYMBOLIC_LINK_FLAG_DIRECTORY
4692 #define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1
4693 #endif
4694
4695 int
4696 symlink (char const *filename, char const *linkname)
4697 {
4698 char linkfn[MAX_PATH], *tgtfn;
4699 DWORD flags = 0;
4700 int dir_access, filename_ends_in_slash;
4701 int dbcs_p;
4702
4703 /* Diagnostics follows Posix as much as possible. */
4704 if (filename == NULL || linkname == NULL)
4705 {
4706 errno = EFAULT;
4707 return -1;
4708 }
4709 if (!*filename)
4710 {
4711 errno = ENOENT;
4712 return -1;
4713 }
4714 if (strlen (filename) > MAX_PATH || strlen (linkname) > MAX_PATH)
4715 {
4716 errno = ENAMETOOLONG;
4717 return -1;
4718 }
4719
4720 strcpy (linkfn, map_w32_filename (linkname, NULL));
4721 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) == 0)
4722 {
4723 errno = EPERM;
4724 return -1;
4725 }
4726
4727 dbcs_p = max_filename_mbslen () > 1;
4728
4729 /* Note: since empty FILENAME was already rejected, we can safely
4730 refer to FILENAME[1]. */
4731 if (!(IS_DIRECTORY_SEP (filename[0]) || IS_DEVICE_SEP (filename[1])))
4732 {
4733 /* Non-absolute FILENAME is understood as being relative to
4734 LINKNAME's directory. We need to prepend that directory to
4735 FILENAME to get correct results from faccessat below, since
4736 otherwise it will interpret FILENAME relative to the
4737 directory where the Emacs process runs. Note that
4738 make-symbolic-link always makes sure LINKNAME is a fully
4739 expanded file name. */
4740 char tem[MAX_PATH];
4741 char *p = linkfn + strlen (linkfn);
4742
4743 if (!dbcs_p)
4744 {
4745 while (p > linkfn && !IS_ANY_SEP (p[-1]))
4746 p--;
4747 }
4748 else
4749 {
4750 char *p1 = CharPrevExA (file_name_codepage, linkfn, p, 0);
4751
4752 while (p > linkfn && !IS_ANY_SEP (*p1))
4753 {
4754 p = p1;
4755 p1 = CharPrevExA (file_name_codepage, linkfn, p1, 0);
4756 }
4757 }
4758 if (p > linkfn)
4759 strncpy (tem, linkfn, p - linkfn);
4760 tem[p - linkfn] = '\0';
4761 strcat (tem, filename);
4762 dir_access = faccessat (AT_FDCWD, tem, D_OK, AT_EACCESS);
4763 }
4764 else
4765 dir_access = faccessat (AT_FDCWD, filename, D_OK, AT_EACCESS);
4766
4767 /* Since Windows distinguishes between symlinks to directories and
4768 to files, we provide a kludgy feature: if FILENAME doesn't
4769 exist, but ends in a slash, we create a symlink to directory. If
4770 FILENAME exists and is a directory, we always create a symlink to
4771 directory. */
4772 if (!dbcs_p)
4773 filename_ends_in_slash = IS_DIRECTORY_SEP (filename[strlen (filename) - 1]);
4774 else
4775 {
4776 const char *end = filename + strlen (filename);
4777 const char *n = CharPrevExA (file_name_codepage, filename, end, 0);
4778
4779 filename_ends_in_slash = IS_DIRECTORY_SEP (*n);
4780 }
4781 if (dir_access == 0 || filename_ends_in_slash)
4782 flags = SYMBOLIC_LINK_FLAG_DIRECTORY;
4783
4784 tgtfn = (char *)map_w32_filename (filename, NULL);
4785 if (filename_ends_in_slash)
4786 tgtfn[strlen (tgtfn) - 1] = '\0';
4787
4788 errno = 0;
4789 if (!create_symbolic_link (linkfn, tgtfn, flags))
4790 {
4791 /* ENOSYS is set by create_symbolic_link, when it detects that
4792 the OS doesn't support the CreateSymbolicLink API. */
4793 if (errno != ENOSYS)
4794 {
4795 DWORD w32err = GetLastError ();
4796
4797 switch (w32err)
4798 {
4799 /* ERROR_SUCCESS is sometimes returned when LINKFN and
4800 TGTFN point to the same file name, go figure. */
4801 case ERROR_SUCCESS:
4802 case ERROR_FILE_EXISTS:
4803 errno = EEXIST;
4804 break;
4805 case ERROR_ACCESS_DENIED:
4806 errno = EACCES;
4807 break;
4808 case ERROR_FILE_NOT_FOUND:
4809 case ERROR_PATH_NOT_FOUND:
4810 case ERROR_BAD_NETPATH:
4811 case ERROR_INVALID_REPARSE_DATA:
4812 errno = ENOENT;
4813 break;
4814 case ERROR_DIRECTORY:
4815 errno = EISDIR;
4816 break;
4817 case ERROR_PRIVILEGE_NOT_HELD:
4818 case ERROR_NOT_ALL_ASSIGNED:
4819 errno = EPERM;
4820 break;
4821 case ERROR_DISK_FULL:
4822 errno = ENOSPC;
4823 break;
4824 default:
4825 errno = EINVAL;
4826 break;
4827 }
4828 }
4829 return -1;
4830 }
4831 return 0;
4832 }
4833
4834 /* A quick inexpensive test of whether FILENAME identifies a file that
4835 is a symlink. Returns non-zero if it is, zero otherwise. FILENAME
4836 must already be in the normalized form returned by
4837 map_w32_filename.
4838
4839 Note: for repeated operations on many files, it is best to test
4840 whether the underlying volume actually supports symlinks, by
4841 testing the FILE_SUPPORTS_REPARSE_POINTS bit in volume's flags, and
4842 avoid the call to this function if it doesn't. That's because the
4843 call to GetFileAttributes takes a non-negligible time, especially
4844 on non-local or removable filesystems. See stat_worker for an
4845 example of how to do that. */
4846 static int
4847 is_symlink (const char *filename)
4848 {
4849 DWORD attrs;
4850 WIN32_FIND_DATA wfd;
4851 HANDLE fh;
4852
4853 attrs = GetFileAttributes (filename);
4854 if (attrs == -1)
4855 {
4856 DWORD w32err = GetLastError ();
4857
4858 switch (w32err)
4859 {
4860 case ERROR_BAD_NETPATH: /* network share, can't be a symlink */
4861 break;
4862 case ERROR_ACCESS_DENIED:
4863 errno = EACCES;
4864 break;
4865 case ERROR_FILE_NOT_FOUND:
4866 case ERROR_PATH_NOT_FOUND:
4867 default:
4868 errno = ENOENT;
4869 break;
4870 }
4871 return 0;
4872 }
4873 if ((attrs & FILE_ATTRIBUTE_REPARSE_POINT) == 0)
4874 return 0;
4875 logon_network_drive (filename);
4876 fh = FindFirstFile (filename, &wfd);
4877 if (fh == INVALID_HANDLE_VALUE)
4878 return 0;
4879 FindClose (fh);
4880 return (wfd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0
4881 && (wfd.dwReserved0 & IO_REPARSE_TAG_SYMLINK) == IO_REPARSE_TAG_SYMLINK;
4882 }
4883
4884 /* If NAME identifies a symbolic link, copy into BUF the file name of
4885 the symlink's target. Copy at most BUF_SIZE bytes, and do NOT
4886 null-terminate the target name, even if it fits. Return the number
4887 of bytes copied, or -1 if NAME is not a symlink or any error was
4888 encountered while resolving it. The file name copied into BUF is
4889 encoded in the current ANSI codepage. */
4890 ssize_t
4891 readlink (const char *name, char *buf, size_t buf_size)
4892 {
4893 const char *path;
4894 TOKEN_PRIVILEGES privs;
4895 int restore_privs = 0;
4896 HANDLE sh;
4897 ssize_t retval;
4898
4899 if (name == NULL)
4900 {
4901 errno = EFAULT;
4902 return -1;
4903 }
4904 if (!*name)
4905 {
4906 errno = ENOENT;
4907 return -1;
4908 }
4909
4910 path = map_w32_filename (name, NULL);
4911
4912 if (strlen (path) > MAX_PATH)
4913 {
4914 errno = ENAMETOOLONG;
4915 return -1;
4916 }
4917
4918 errno = 0;
4919 if (is_windows_9x () == TRUE
4920 || (volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) == 0
4921 || !is_symlink (path))
4922 {
4923 if (!errno)
4924 errno = EINVAL; /* not a symlink */
4925 return -1;
4926 }
4927
4928 /* Done with simple tests, now we're in for some _real_ work. */
4929 if (enable_privilege (SE_BACKUP_NAME, TRUE, &privs))
4930 restore_privs = 1;
4931 /* Implementation note: From here and onward, don't return early,
4932 since that will fail to restore the original set of privileges of
4933 the calling thread. */
4934
4935 retval = -1; /* not too optimistic, are we? */
4936
4937 /* Note: In the next call to CreateFile, we use zero as the 2nd
4938 argument because, when the symlink is a hidden/system file,
4939 e.g. 'C:\Users\All Users', GENERIC_READ fails with
4940 ERROR_ACCESS_DENIED. Zero seems to work just fine, both for file
4941 and directory symlinks. */
4942 sh = CreateFile (path, 0, 0, NULL, OPEN_EXISTING,
4943 FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
4944 NULL);
4945 if (sh != INVALID_HANDLE_VALUE)
4946 {
4947 BYTE reparse_buf[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
4948 REPARSE_DATA_BUFFER *reparse_data = (REPARSE_DATA_BUFFER *)&reparse_buf[0];
4949 DWORD retbytes;
4950
4951 if (!DeviceIoControl (sh, FSCTL_GET_REPARSE_POINT, NULL, 0,
4952 reparse_buf, MAXIMUM_REPARSE_DATA_BUFFER_SIZE,
4953 &retbytes, NULL))
4954 errno = EIO;
4955 else if (reparse_data->ReparseTag != IO_REPARSE_TAG_SYMLINK)
4956 errno = EINVAL;
4957 else
4958 {
4959 /* Copy the link target name, in wide characters, from
4960 reparse_data, then convert it to multibyte encoding in
4961 the current locale's codepage. */
4962 WCHAR *lwname;
4963 BYTE lname[MAX_PATH];
4964 USHORT lname_len;
4965 USHORT lwname_len =
4966 reparse_data->SymbolicLinkReparseBuffer.PrintNameLength;
4967 WCHAR *lwname_src =
4968 reparse_data->SymbolicLinkReparseBuffer.PathBuffer
4969 + reparse_data->SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(WCHAR);
4970 /* This updates file_name_codepage which we need below. */
4971 int dbcs_p = max_filename_mbslen () > 1;
4972
4973 /* According to MSDN, PrintNameLength does not include the
4974 terminating null character. */
4975 lwname = alloca ((lwname_len + 1) * sizeof(WCHAR));
4976 memcpy (lwname, lwname_src, lwname_len);
4977 lwname[lwname_len/sizeof(WCHAR)] = 0; /* null-terminate */
4978
4979 lname_len = WideCharToMultiByte (file_name_codepage, 0, lwname, -1,
4980 lname, MAX_PATH, NULL, NULL);
4981 if (!lname_len)
4982 {
4983 /* WideCharToMultiByte failed. */
4984 DWORD w32err1 = GetLastError ();
4985
4986 switch (w32err1)
4987 {
4988 case ERROR_INSUFFICIENT_BUFFER:
4989 errno = ENAMETOOLONG;
4990 break;
4991 case ERROR_INVALID_PARAMETER:
4992 errno = EFAULT;
4993 break;
4994 case ERROR_NO_UNICODE_TRANSLATION:
4995 errno = ENOENT;
4996 break;
4997 default:
4998 errno = EINVAL;
4999 break;
5000 }
5001 }
5002 else
5003 {
5004 size_t size_to_copy = buf_size;
5005 BYTE *p = lname, *p2;
5006 BYTE *pend = p + lname_len;
5007
5008 /* Normalize like dostounix_filename does, but we don't
5009 want to assume that lname is null-terminated. */
5010 if (dbcs_p)
5011 p2 = CharNextExA (file_name_codepage, p, 0);
5012 else
5013 p2 = p + 1;
5014 if (*p && *p2 == ':' && *p >= 'A' && *p <= 'Z')
5015 {
5016 *p += 'a' - 'A';
5017 p += 2;
5018 }
5019 while (p <= pend)
5020 {
5021 if (*p == '\\')
5022 *p = '/';
5023 if (dbcs_p)
5024 {
5025 p = CharNextExA (file_name_codepage, p, 0);
5026 /* CharNextExA doesn't advance at null character. */
5027 if (!*p)
5028 break;
5029 }
5030 else
5031 ++p;
5032 }
5033 /* Testing for null-terminated LNAME is paranoia:
5034 WideCharToMultiByte should always return a
5035 null-terminated string when its 4th argument is -1
5036 and its 3rd argument is null-terminated (which they
5037 are, see above). */
5038 if (lname[lname_len - 1] == '\0')
5039 lname_len--;
5040 if (lname_len <= buf_size)
5041 size_to_copy = lname_len;
5042 strncpy (buf, lname, size_to_copy);
5043 /* Success! */
5044 retval = size_to_copy;
5045 }
5046 }
5047 CloseHandle (sh);
5048 }
5049 else
5050 {
5051 /* CreateFile failed. */
5052 DWORD w32err2 = GetLastError ();
5053
5054 switch (w32err2)
5055 {
5056 case ERROR_FILE_NOT_FOUND:
5057 case ERROR_PATH_NOT_FOUND:
5058 errno = ENOENT;
5059 break;
5060 case ERROR_ACCESS_DENIED:
5061 case ERROR_TOO_MANY_OPEN_FILES:
5062 errno = EACCES;
5063 break;
5064 default:
5065 errno = EPERM;
5066 break;
5067 }
5068 }
5069 if (restore_privs)
5070 {
5071 restore_privilege (&privs);
5072 revert_to_self ();
5073 }
5074
5075 return retval;
5076 }
5077
5078 ssize_t
5079 readlinkat (int fd, char const *name, char *buffer,
5080 size_t buffer_size)
5081 {
5082 /* Rely on a hack: an open directory is modeled as file descriptor 0,
5083 as in fstatat. FIXME: Add proper support for readlinkat. */
5084 char fullname[MAX_PATH];
5085
5086 if (fd != AT_FDCWD)
5087 {
5088 if (_snprintf (fullname, sizeof fullname, "%s/%s", dir_pathname, name)
5089 < 0)
5090 {
5091 errno = ENAMETOOLONG;
5092 return -1;
5093 }
5094 name = fullname;
5095 }
5096
5097 return readlink (name, buffer, buffer_size);
5098 }
5099
5100 /* If FILE is a symlink, return its target (stored in a static
5101 buffer); otherwise return FILE.
5102
5103 This function repeatedly resolves symlinks in the last component of
5104 a chain of symlink file names, as in foo -> bar -> baz -> ...,
5105 until it arrives at a file whose last component is not a symlink,
5106 or some error occurs. It returns the target of the last
5107 successfully resolved symlink in the chain. If it succeeds to
5108 resolve even a single symlink, the value returned is an absolute
5109 file name with backslashes (result of GetFullPathName). By
5110 contrast, if the original FILE is returned, it is unaltered.
5111
5112 Note: This function can set errno even if it succeeds.
5113
5114 Implementation note: we only resolve the last portion ("basename")
5115 of the argument FILE and of each following file in the chain,
5116 disregarding any possible symlinks in its leading directories.
5117 This is because Windows system calls and library functions
5118 transparently resolve symlinks in leading directories and return
5119 correct information, as long as the basename is not a symlink. */
5120 static char *
5121 chase_symlinks (const char *file)
5122 {
5123 static char target[MAX_PATH];
5124 char link[MAX_PATH];
5125 ssize_t res, link_len;
5126 int loop_count = 0;
5127 int dbcs_p;
5128
5129 if (is_windows_9x () == TRUE || !is_symlink (file))
5130 return (char *)file;
5131
5132 if ((link_len = GetFullPathName (file, MAX_PATH, link, NULL)) == 0)
5133 return (char *)file;
5134
5135 dbcs_p = max_filename_mbslen () > 1;
5136 target[0] = '\0';
5137 do {
5138
5139 /* Remove trailing slashes, as we want to resolve the last
5140 non-trivial part of the link name. */
5141 if (!dbcs_p)
5142 {
5143 while (link_len > 3 && IS_DIRECTORY_SEP (link[link_len-1]))
5144 link[link_len--] = '\0';
5145 }
5146 else if (link_len > 3)
5147 {
5148 char *n = CharPrevExA (file_name_codepage, link, link + link_len, 0);
5149
5150 while (n >= link + 2 && IS_DIRECTORY_SEP (*n))
5151 {
5152 n[1] = '\0';
5153 n = CharPrevExA (file_name_codepage, link, n, 0);
5154 }
5155 }
5156
5157 res = readlink (link, target, MAX_PATH);
5158 if (res > 0)
5159 {
5160 target[res] = '\0';
5161 if (!(IS_DEVICE_SEP (target[1])
5162 || (IS_DIRECTORY_SEP (target[0]) && IS_DIRECTORY_SEP (target[1]))))
5163 {
5164 /* Target is relative. Append it to the directory part of
5165 the symlink, then copy the result back to target. */
5166 char *p = link + link_len;
5167
5168 if (!dbcs_p)
5169 {
5170 while (p > link && !IS_ANY_SEP (p[-1]))
5171 p--;
5172 }
5173 else
5174 {
5175 char *p1 = CharPrevExA (file_name_codepage, link, p, 0);
5176
5177 while (p > link && !IS_ANY_SEP (*p1))
5178 {
5179 p = p1;
5180 p1 = CharPrevExA (file_name_codepage, link, p1, 0);
5181 }
5182 }
5183 strcpy (p, target);
5184 strcpy (target, link);
5185 }
5186 /* Resolve any "." and ".." to get a fully-qualified file name
5187 in link[] again. */
5188 link_len = GetFullPathName (target, MAX_PATH, link, NULL);
5189 }
5190 } while (res > 0 && link_len > 0 && ++loop_count <= 100);
5191
5192 if (loop_count > 100)
5193 errno = ELOOP;
5194
5195 if (target[0] == '\0') /* not a single call to readlink succeeded */
5196 return (char *)file;
5197 return target;
5198 }
5199
5200 \f
5201 /* Posix ACL emulation. */
5202
5203 int
5204 acl_valid (acl_t acl)
5205 {
5206 return is_valid_security_descriptor ((PSECURITY_DESCRIPTOR)acl) ? 0 : -1;
5207 }
5208
5209 char *
5210 acl_to_text (acl_t acl, ssize_t *size)
5211 {
5212 LPTSTR str_acl;
5213 SECURITY_INFORMATION flags =
5214 OWNER_SECURITY_INFORMATION |
5215 GROUP_SECURITY_INFORMATION |
5216 DACL_SECURITY_INFORMATION;
5217 char *retval = NULL;
5218 ULONG local_size;
5219 int e = errno;
5220
5221 errno = 0;
5222
5223 if (convert_sd_to_sddl ((PSECURITY_DESCRIPTOR)acl, SDDL_REVISION_1, flags, &str_acl, &local_size))
5224 {
5225 errno = e;
5226 /* We don't want to mix heaps, so we duplicate the string in our
5227 heap and free the one allocated by the API. */
5228 retval = xstrdup (str_acl);
5229 if (size)
5230 *size = local_size;
5231 LocalFree (str_acl);
5232 }
5233 else if (errno != ENOTSUP)
5234 errno = EINVAL;
5235
5236 return retval;
5237 }
5238
5239 acl_t
5240 acl_from_text (const char *acl_str)
5241 {
5242 PSECURITY_DESCRIPTOR psd, retval = NULL;
5243 ULONG sd_size;
5244 int e = errno;
5245
5246 errno = 0;
5247
5248 if (convert_sddl_to_sd (acl_str, SDDL_REVISION_1, &psd, &sd_size))
5249 {
5250 errno = e;
5251 retval = xmalloc (sd_size);
5252 memcpy (retval, psd, sd_size);
5253 LocalFree (psd);
5254 }
5255 else if (errno != ENOTSUP)
5256 errno = EINVAL;
5257
5258 return retval;
5259 }
5260
5261 int
5262 acl_free (void *ptr)
5263 {
5264 xfree (ptr);
5265 return 0;
5266 }
5267
5268 acl_t
5269 acl_get_file (const char *fname, acl_type_t type)
5270 {
5271 PSECURITY_DESCRIPTOR psd = NULL;
5272 const char *filename;
5273
5274 if (type == ACL_TYPE_ACCESS)
5275 {
5276 DWORD sd_len, err;
5277 SECURITY_INFORMATION si =
5278 OWNER_SECURITY_INFORMATION |
5279 GROUP_SECURITY_INFORMATION |
5280 DACL_SECURITY_INFORMATION ;
5281 int e = errno;
5282
5283 filename = map_w32_filename (fname, NULL);
5284 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
5285 fname = chase_symlinks (filename);
5286 else
5287 fname = filename;
5288
5289 errno = 0;
5290 if (!get_file_security (fname, si, psd, 0, &sd_len)
5291 && errno != ENOTSUP)
5292 {
5293 err = GetLastError ();
5294 if (err == ERROR_INSUFFICIENT_BUFFER)
5295 {
5296 psd = xmalloc (sd_len);
5297 if (!get_file_security (fname, si, psd, sd_len, &sd_len))
5298 {
5299 xfree (psd);
5300 errno = EIO;
5301 psd = NULL;
5302 }
5303 }
5304 else if (err == ERROR_FILE_NOT_FOUND
5305 || err == ERROR_PATH_NOT_FOUND)
5306 errno = ENOENT;
5307 else
5308 errno = EIO;
5309 }
5310 else if (!errno)
5311 errno = e;
5312 }
5313 else if (type != ACL_TYPE_DEFAULT)
5314 errno = EINVAL;
5315
5316 return psd;
5317 }
5318
5319 int
5320 acl_set_file (const char *fname, acl_type_t type, acl_t acl)
5321 {
5322 TOKEN_PRIVILEGES old1, old2;
5323 DWORD err;
5324 int st = 0, retval = -1;
5325 SECURITY_INFORMATION flags = 0;
5326 PSID psid;
5327 PACL pacl;
5328 BOOL dflt;
5329 BOOL dacl_present;
5330 int e;
5331 const char *filename;
5332
5333 if (acl_valid (acl) != 0
5334 || (type != ACL_TYPE_DEFAULT && type != ACL_TYPE_ACCESS))
5335 {
5336 errno = EINVAL;
5337 return -1;
5338 }
5339
5340 if (type == ACL_TYPE_DEFAULT)
5341 {
5342 errno = ENOSYS;
5343 return -1;
5344 }
5345
5346 filename = map_w32_filename (fname, NULL);
5347 if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0)
5348 fname = chase_symlinks (filename);
5349 else
5350 fname = filename;
5351
5352 if (get_security_descriptor_owner ((PSECURITY_DESCRIPTOR)acl, &psid, &dflt)
5353 && psid)
5354 flags |= OWNER_SECURITY_INFORMATION;
5355 if (get_security_descriptor_group ((PSECURITY_DESCRIPTOR)acl, &psid, &dflt)
5356 && psid)
5357 flags |= GROUP_SECURITY_INFORMATION;
5358 if (get_security_descriptor_dacl ((PSECURITY_DESCRIPTOR)acl, &dacl_present,
5359 &pacl, &dflt)
5360 && dacl_present)
5361 flags |= DACL_SECURITY_INFORMATION;
5362 if (!flags)
5363 return 0;
5364
5365 /* According to KB-245153, setting the owner will succeed if either:
5366 (1) the caller is the user who will be the new owner, and has the
5367 SE_TAKE_OWNERSHIP privilege, or
5368 (2) the caller has the SE_RESTORE privilege, in which case she can
5369 set any valid user or group as the owner
5370
5371 We request below both SE_TAKE_OWNERSHIP and SE_RESTORE
5372 privileges, and disregard any failures in obtaining them. If
5373 these privileges cannot be obtained, and do not already exist in
5374 the calling thread's security token, this function could fail
5375 with EPERM. */
5376 if (enable_privilege (SE_TAKE_OWNERSHIP_NAME, TRUE, &old1))
5377 st++;
5378 if (enable_privilege (SE_RESTORE_NAME, TRUE, &old2))
5379 st++;
5380
5381 e = errno;
5382 errno = 0;
5383 if (!set_file_security ((char *)fname, flags, (PSECURITY_DESCRIPTOR)acl))
5384 {
5385 err = GetLastError ();
5386
5387 if (errno == ENOTSUP)
5388 ;
5389 else if (err == ERROR_INVALID_OWNER
5390 || err == ERROR_NOT_ALL_ASSIGNED
5391 || err == ERROR_ACCESS_DENIED)
5392 {
5393 /* Maybe the requested ACL and the one the file already has
5394 are identical, in which case we can silently ignore the
5395 failure. (And no, Windows doesn't.) */
5396 acl_t current_acl = acl_get_file (fname, ACL_TYPE_ACCESS);
5397
5398 errno = EPERM;
5399 if (current_acl)
5400 {
5401 char *acl_from = acl_to_text (current_acl, NULL);
5402 char *acl_to = acl_to_text (acl, NULL);
5403
5404 if (acl_from && acl_to && xstrcasecmp (acl_from, acl_to) == 0)
5405 {
5406 retval = 0;
5407 errno = e;
5408 }
5409 if (acl_from)
5410 acl_free (acl_from);
5411 if (acl_to)
5412 acl_free (acl_to);
5413 acl_free (current_acl);
5414 }
5415 }
5416 else if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND)
5417 errno = ENOENT;
5418 else
5419 errno = EACCES;
5420 }
5421 else
5422 {
5423 retval = 0;
5424 errno = e;
5425 }
5426
5427 if (st)
5428 {
5429 if (st >= 2)
5430 restore_privilege (&old2);
5431 restore_privilege (&old1);
5432 revert_to_self ();
5433 }
5434
5435 return retval;
5436 }
5437
5438 \f
5439 /* MS-Windows version of careadlinkat (cf. ../lib/careadlinkat.c). We
5440 have a fixed max size for file names, so we don't need the kind of
5441 alloc/malloc/realloc dance the gnulib version does. We also don't
5442 support FD-relative symlinks. */
5443 char *
5444 careadlinkat (int fd, char const *filename,
5445 char *buffer, size_t buffer_size,
5446 struct allocator const *alloc,
5447 ssize_t (*preadlinkat) (int, char const *, char *, size_t))
5448 {
5449 char linkname[MAX_PATH];
5450 ssize_t link_size;
5451
5452 link_size = preadlinkat (fd, filename, linkname, sizeof(linkname));
5453
5454 if (link_size > 0)
5455 {
5456 char *retval = buffer;
5457
5458 linkname[link_size++] = '\0';
5459 if (link_size > buffer_size)
5460 retval = (char *)(alloc ? alloc->allocate : xmalloc) (link_size);
5461 if (retval)
5462 memcpy (retval, linkname, link_size);
5463
5464 return retval;
5465 }
5466 return NULL;
5467 }
5468
5469 \f
5470 /* Support for browsing other processes and their attributes. See
5471 process.c for the Lisp bindings. */
5472
5473 /* Helper wrapper functions. */
5474
5475 static HANDLE WINAPI
5476 create_toolhelp32_snapshot (DWORD Flags, DWORD Ignored)
5477 {
5478 static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot = NULL;
5479
5480 if (g_b_init_create_toolhelp32_snapshot == 0)
5481 {
5482 g_b_init_create_toolhelp32_snapshot = 1;
5483 s_pfn_Create_Toolhelp32_Snapshot = (CreateToolhelp32Snapshot_Proc)
5484 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5485 "CreateToolhelp32Snapshot");
5486 }
5487 if (s_pfn_Create_Toolhelp32_Snapshot == NULL)
5488 {
5489 return INVALID_HANDLE_VALUE;
5490 }
5491 return (s_pfn_Create_Toolhelp32_Snapshot (Flags, Ignored));
5492 }
5493
5494 static BOOL WINAPI
5495 process32_first (HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
5496 {
5497 static Process32First_Proc s_pfn_Process32_First = NULL;
5498
5499 if (g_b_init_process32_first == 0)
5500 {
5501 g_b_init_process32_first = 1;
5502 s_pfn_Process32_First = (Process32First_Proc)
5503 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5504 "Process32First");
5505 }
5506 if (s_pfn_Process32_First == NULL)
5507 {
5508 return FALSE;
5509 }
5510 return (s_pfn_Process32_First (hSnapshot, lppe));
5511 }
5512
5513 static BOOL WINAPI
5514 process32_next (HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
5515 {
5516 static Process32Next_Proc s_pfn_Process32_Next = NULL;
5517
5518 if (g_b_init_process32_next == 0)
5519 {
5520 g_b_init_process32_next = 1;
5521 s_pfn_Process32_Next = (Process32Next_Proc)
5522 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5523 "Process32Next");
5524 }
5525 if (s_pfn_Process32_Next == NULL)
5526 {
5527 return FALSE;
5528 }
5529 return (s_pfn_Process32_Next (hSnapshot, lppe));
5530 }
5531
5532 static BOOL WINAPI
5533 open_thread_token (HANDLE ThreadHandle,
5534 DWORD DesiredAccess,
5535 BOOL OpenAsSelf,
5536 PHANDLE TokenHandle)
5537 {
5538 static OpenThreadToken_Proc s_pfn_Open_Thread_Token = NULL;
5539 HMODULE hm_advapi32 = NULL;
5540 if (is_windows_9x () == TRUE)
5541 {
5542 SetLastError (ERROR_NOT_SUPPORTED);
5543 return FALSE;
5544 }
5545 if (g_b_init_open_thread_token == 0)
5546 {
5547 g_b_init_open_thread_token = 1;
5548 hm_advapi32 = LoadLibrary ("Advapi32.dll");
5549 s_pfn_Open_Thread_Token =
5550 (OpenThreadToken_Proc) GetProcAddress (hm_advapi32, "OpenThreadToken");
5551 }
5552 if (s_pfn_Open_Thread_Token == NULL)
5553 {
5554 SetLastError (ERROR_NOT_SUPPORTED);
5555 return FALSE;
5556 }
5557 return (
5558 s_pfn_Open_Thread_Token (
5559 ThreadHandle,
5560 DesiredAccess,
5561 OpenAsSelf,
5562 TokenHandle)
5563 );
5564 }
5565
5566 static BOOL WINAPI
5567 impersonate_self (SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
5568 {
5569 static ImpersonateSelf_Proc s_pfn_Impersonate_Self = NULL;
5570 HMODULE hm_advapi32 = NULL;
5571 if (is_windows_9x () == TRUE)
5572 {
5573 return FALSE;
5574 }
5575 if (g_b_init_impersonate_self == 0)
5576 {
5577 g_b_init_impersonate_self = 1;
5578 hm_advapi32 = LoadLibrary ("Advapi32.dll");
5579 s_pfn_Impersonate_Self =
5580 (ImpersonateSelf_Proc) GetProcAddress (hm_advapi32, "ImpersonateSelf");
5581 }
5582 if (s_pfn_Impersonate_Self == NULL)
5583 {
5584 return FALSE;
5585 }
5586 return s_pfn_Impersonate_Self (ImpersonationLevel);
5587 }
5588
5589 static BOOL WINAPI
5590 revert_to_self (void)
5591 {
5592 static RevertToSelf_Proc s_pfn_Revert_To_Self = NULL;
5593 HMODULE hm_advapi32 = NULL;
5594 if (is_windows_9x () == TRUE)
5595 {
5596 return FALSE;
5597 }
5598 if (g_b_init_revert_to_self == 0)
5599 {
5600 g_b_init_revert_to_self = 1;
5601 hm_advapi32 = LoadLibrary ("Advapi32.dll");
5602 s_pfn_Revert_To_Self =
5603 (RevertToSelf_Proc) GetProcAddress (hm_advapi32, "RevertToSelf");
5604 }
5605 if (s_pfn_Revert_To_Self == NULL)
5606 {
5607 return FALSE;
5608 }
5609 return s_pfn_Revert_To_Self ();
5610 }
5611
5612 static BOOL WINAPI
5613 get_process_memory_info (HANDLE h_proc,
5614 PPROCESS_MEMORY_COUNTERS mem_counters,
5615 DWORD bufsize)
5616 {
5617 static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info = NULL;
5618 HMODULE hm_psapi = NULL;
5619 if (is_windows_9x () == TRUE)
5620 {
5621 return FALSE;
5622 }
5623 if (g_b_init_get_process_memory_info == 0)
5624 {
5625 g_b_init_get_process_memory_info = 1;
5626 hm_psapi = LoadLibrary ("Psapi.dll");
5627 if (hm_psapi)
5628 s_pfn_Get_Process_Memory_Info = (GetProcessMemoryInfo_Proc)
5629 GetProcAddress (hm_psapi, "GetProcessMemoryInfo");
5630 }
5631 if (s_pfn_Get_Process_Memory_Info == NULL)
5632 {
5633 return FALSE;
5634 }
5635 return s_pfn_Get_Process_Memory_Info (h_proc, mem_counters, bufsize);
5636 }
5637
5638 static BOOL WINAPI
5639 get_process_working_set_size (HANDLE h_proc,
5640 PSIZE_T minrss,
5641 PSIZE_T maxrss)
5642 {
5643 static GetProcessWorkingSetSize_Proc
5644 s_pfn_Get_Process_Working_Set_Size = NULL;
5645
5646 if (is_windows_9x () == TRUE)
5647 {
5648 return FALSE;
5649 }
5650 if (g_b_init_get_process_working_set_size == 0)
5651 {
5652 g_b_init_get_process_working_set_size = 1;
5653 s_pfn_Get_Process_Working_Set_Size = (GetProcessWorkingSetSize_Proc)
5654 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5655 "GetProcessWorkingSetSize");
5656 }
5657 if (s_pfn_Get_Process_Working_Set_Size == NULL)
5658 {
5659 return FALSE;
5660 }
5661 return s_pfn_Get_Process_Working_Set_Size (h_proc, minrss, maxrss);
5662 }
5663
5664 static BOOL WINAPI
5665 global_memory_status (MEMORYSTATUS *buf)
5666 {
5667 static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status = NULL;
5668
5669 if (is_windows_9x () == TRUE)
5670 {
5671 return FALSE;
5672 }
5673 if (g_b_init_global_memory_status == 0)
5674 {
5675 g_b_init_global_memory_status = 1;
5676 s_pfn_Global_Memory_Status = (GlobalMemoryStatus_Proc)
5677 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5678 "GlobalMemoryStatus");
5679 }
5680 if (s_pfn_Global_Memory_Status == NULL)
5681 {
5682 return FALSE;
5683 }
5684 return s_pfn_Global_Memory_Status (buf);
5685 }
5686
5687 static BOOL WINAPI
5688 global_memory_status_ex (MEMORY_STATUS_EX *buf)
5689 {
5690 static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex = NULL;
5691
5692 if (is_windows_9x () == TRUE)
5693 {
5694 return FALSE;
5695 }
5696 if (g_b_init_global_memory_status_ex == 0)
5697 {
5698 g_b_init_global_memory_status_ex = 1;
5699 s_pfn_Global_Memory_Status_Ex = (GlobalMemoryStatusEx_Proc)
5700 GetProcAddress (GetModuleHandle ("kernel32.dll"),
5701 "GlobalMemoryStatusEx");
5702 }
5703 if (s_pfn_Global_Memory_Status_Ex == NULL)
5704 {
5705 return FALSE;
5706 }
5707 return s_pfn_Global_Memory_Status_Ex (buf);
5708 }
5709
5710 Lisp_Object
5711 list_system_processes (void)
5712 {
5713 struct gcpro gcpro1;
5714 Lisp_Object proclist = Qnil;
5715 HANDLE h_snapshot;
5716
5717 h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
5718
5719 if (h_snapshot != INVALID_HANDLE_VALUE)
5720 {
5721 PROCESSENTRY32 proc_entry;
5722 DWORD proc_id;
5723 BOOL res;
5724
5725 GCPRO1 (proclist);
5726
5727 proc_entry.dwSize = sizeof (PROCESSENTRY32);
5728 for (res = process32_first (h_snapshot, &proc_entry); res;
5729 res = process32_next (h_snapshot, &proc_entry))
5730 {
5731 proc_id = proc_entry.th32ProcessID;
5732 proclist = Fcons (make_fixnum_or_float (proc_id), proclist);
5733 }
5734
5735 CloseHandle (h_snapshot);
5736 UNGCPRO;
5737 proclist = Fnreverse (proclist);
5738 }
5739
5740 return proclist;
5741 }
5742
5743 static int
5744 enable_privilege (LPCTSTR priv_name, BOOL enable_p, TOKEN_PRIVILEGES *old_priv)
5745 {
5746 TOKEN_PRIVILEGES priv;
5747 DWORD priv_size = sizeof (priv);
5748 DWORD opriv_size = sizeof (*old_priv);
5749 HANDLE h_token = NULL;
5750 HANDLE h_thread = GetCurrentThread ();
5751 int ret_val = 0;
5752 BOOL res;
5753
5754 res = open_thread_token (h_thread,
5755 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
5756 FALSE, &h_token);
5757 if (!res && GetLastError () == ERROR_NO_TOKEN)
5758 {
5759 if (impersonate_self (SecurityImpersonation))
5760 res = open_thread_token (h_thread,
5761 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
5762 FALSE, &h_token);
5763 }
5764 if (res)
5765 {
5766 priv.PrivilegeCount = 1;
5767 priv.Privileges[0].Attributes = enable_p ? SE_PRIVILEGE_ENABLED : 0;
5768 LookupPrivilegeValue (NULL, priv_name, &priv.Privileges[0].Luid);
5769 if (AdjustTokenPrivileges (h_token, FALSE, &priv, priv_size,
5770 old_priv, &opriv_size)
5771 && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
5772 ret_val = 1;
5773 }
5774 if (h_token)
5775 CloseHandle (h_token);
5776
5777 return ret_val;
5778 }
5779
5780 static int
5781 restore_privilege (TOKEN_PRIVILEGES *priv)
5782 {
5783 DWORD priv_size = sizeof (*priv);
5784 HANDLE h_token = NULL;
5785 int ret_val = 0;
5786
5787 if (open_thread_token (GetCurrentThread (),
5788 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
5789 FALSE, &h_token))
5790 {
5791 if (AdjustTokenPrivileges (h_token, FALSE, priv, priv_size, NULL, NULL)
5792 && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
5793 ret_val = 1;
5794 }
5795 if (h_token)
5796 CloseHandle (h_token);
5797
5798 return ret_val;
5799 }
5800
5801 static Lisp_Object
5802 ltime (ULONGLONG time_100ns)
5803 {
5804 ULONGLONG time_sec = time_100ns / 10000000;
5805 int subsec = time_100ns % 10000000;
5806 return list4i (time_sec >> 16, time_sec & 0xffff,
5807 subsec / 10, subsec % 10 * 100000);
5808 }
5809
5810 #define U64_TO_LISP_TIME(time) ltime (time)
5811
5812 static int
5813 process_times (HANDLE h_proc, Lisp_Object *ctime, Lisp_Object *etime,
5814 Lisp_Object *stime, Lisp_Object *utime, Lisp_Object *ttime,
5815 double *pcpu)
5816 {
5817 FILETIME ft_creation, ft_exit, ft_kernel, ft_user, ft_current;
5818 ULONGLONG tem1, tem2, tem3, tem;
5819
5820 if (!h_proc
5821 || !get_process_times_fn
5822 || !(*get_process_times_fn) (h_proc, &ft_creation, &ft_exit,
5823 &ft_kernel, &ft_user))
5824 return 0;
5825
5826 GetSystemTimeAsFileTime (&ft_current);
5827
5828 FILETIME_TO_U64 (tem1, ft_kernel);
5829 *stime = U64_TO_LISP_TIME (tem1);
5830
5831 FILETIME_TO_U64 (tem2, ft_user);
5832 *utime = U64_TO_LISP_TIME (tem2);
5833
5834 tem3 = tem1 + tem2;
5835 *ttime = U64_TO_LISP_TIME (tem3);
5836
5837 FILETIME_TO_U64 (tem, ft_creation);
5838 /* Process no 4 (System) returns zero creation time. */
5839 if (tem)
5840 tem -= utc_base;
5841 *ctime = U64_TO_LISP_TIME (tem);
5842
5843 if (tem)
5844 {
5845 FILETIME_TO_U64 (tem3, ft_current);
5846 tem = (tem3 - utc_base) - tem;
5847 }
5848 *etime = U64_TO_LISP_TIME (tem);
5849
5850 if (tem)
5851 {
5852 *pcpu = 100.0 * (tem1 + tem2) / tem;
5853 if (*pcpu > 100)
5854 *pcpu = 100.0;
5855 }
5856 else
5857 *pcpu = 0;
5858
5859 return 1;
5860 }
5861
5862 Lisp_Object
5863 system_process_attributes (Lisp_Object pid)
5864 {
5865 struct gcpro gcpro1, gcpro2, gcpro3;
5866 Lisp_Object attrs = Qnil;
5867 Lisp_Object cmd_str, decoded_cmd, tem;
5868 HANDLE h_snapshot, h_proc;
5869 DWORD proc_id;
5870 int found_proc = 0;
5871 char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
5872 DWORD ulength = sizeof (uname), dlength = sizeof (domain), needed;
5873 DWORD glength = sizeof (gname);
5874 HANDLE token = NULL;
5875 SID_NAME_USE user_type;
5876 unsigned char *buf = NULL;
5877 DWORD blen = 0;
5878 TOKEN_USER user_token;
5879 TOKEN_PRIMARY_GROUP group_token;
5880 unsigned euid;
5881 unsigned egid;
5882 PROCESS_MEMORY_COUNTERS mem;
5883 PROCESS_MEMORY_COUNTERS_EX mem_ex;
5884 SIZE_T minrss, maxrss;
5885 MEMORYSTATUS memst;
5886 MEMORY_STATUS_EX memstex;
5887 double totphys = 0.0;
5888 Lisp_Object ctime, stime, utime, etime, ttime;
5889 double pcpu;
5890 BOOL result = FALSE;
5891
5892 CHECK_NUMBER_OR_FLOAT (pid);
5893 proc_id = FLOATP (pid) ? XFLOAT_DATA (pid) : XINT (pid);
5894
5895 h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
5896
5897 GCPRO3 (attrs, decoded_cmd, tem);
5898
5899 if (h_snapshot != INVALID_HANDLE_VALUE)
5900 {
5901 PROCESSENTRY32 pe;
5902 BOOL res;
5903
5904 pe.dwSize = sizeof (PROCESSENTRY32);
5905 for (res = process32_first (h_snapshot, &pe); res;
5906 res = process32_next (h_snapshot, &pe))
5907 {
5908 if (proc_id == pe.th32ProcessID)
5909 {
5910 if (proc_id == 0)
5911 decoded_cmd = build_string ("Idle");
5912 else
5913 {
5914 /* Decode the command name from locale-specific
5915 encoding. */
5916 cmd_str = build_unibyte_string (pe.szExeFile);
5917
5918 decoded_cmd =
5919 code_convert_string_norecord (cmd_str,
5920 Vlocale_coding_system, 0);
5921 }
5922 attrs = Fcons (Fcons (Qcomm, decoded_cmd), attrs);
5923 attrs = Fcons (Fcons (Qppid,
5924 make_fixnum_or_float (pe.th32ParentProcessID)),
5925 attrs);
5926 attrs = Fcons (Fcons (Qpri, make_number (pe.pcPriClassBase)),
5927 attrs);
5928 attrs = Fcons (Fcons (Qthcount,
5929 make_fixnum_or_float (pe.cntThreads)),
5930 attrs);
5931 found_proc = 1;
5932 break;
5933 }
5934 }
5935
5936 CloseHandle (h_snapshot);
5937 }
5938
5939 if (!found_proc)
5940 {
5941 UNGCPRO;
5942 return Qnil;
5943 }
5944
5945 h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
5946 FALSE, proc_id);
5947 /* If we were denied a handle to the process, try again after
5948 enabling the SeDebugPrivilege in our process. */
5949 if (!h_proc)
5950 {
5951 TOKEN_PRIVILEGES priv_current;
5952
5953 if (enable_privilege (SE_DEBUG_NAME, TRUE, &priv_current))
5954 {
5955 h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
5956 FALSE, proc_id);
5957 restore_privilege (&priv_current);
5958 revert_to_self ();
5959 }
5960 }
5961 if (h_proc)
5962 {
5963 result = open_process_token (h_proc, TOKEN_QUERY, &token);
5964 if (result)
5965 {
5966 result = get_token_information (token, TokenUser, NULL, 0, &blen);
5967 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
5968 {
5969 buf = xmalloc (blen);
5970 result = get_token_information (token, TokenUser,
5971 (LPVOID)buf, blen, &needed);
5972 if (result)
5973 {
5974 memcpy (&user_token, buf, sizeof (user_token));
5975 if (!w32_cached_id (user_token.User.Sid, &euid, uname))
5976 {
5977 euid = get_rid (user_token.User.Sid);
5978 result = lookup_account_sid (NULL, user_token.User.Sid,
5979 uname, &ulength,
5980 domain, &dlength,
5981 &user_type);
5982 if (result)
5983 w32_add_to_cache (user_token.User.Sid, euid, uname);
5984 else
5985 {
5986 strcpy (uname, "unknown");
5987 result = TRUE;
5988 }
5989 }
5990 ulength = strlen (uname);
5991 }
5992 }
5993 }
5994 if (result)
5995 {
5996 /* Determine a reasonable euid and gid values. */
5997 if (xstrcasecmp ("administrator", uname) == 0)
5998 {
5999 euid = 500; /* well-known Administrator uid */
6000 egid = 513; /* well-known None gid */
6001 }
6002 else
6003 {
6004 /* Get group id and name. */
6005 result = get_token_information (token, TokenPrimaryGroup,
6006 (LPVOID)buf, blen, &needed);
6007 if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
6008 {
6009 buf = xrealloc (buf, blen = needed);
6010 result = get_token_information (token, TokenPrimaryGroup,
6011 (LPVOID)buf, blen, &needed);
6012 }
6013 if (result)
6014 {
6015 memcpy (&group_token, buf, sizeof (group_token));
6016 if (!w32_cached_id (group_token.PrimaryGroup, &egid, gname))
6017 {
6018 egid = get_rid (group_token.PrimaryGroup);
6019 dlength = sizeof (domain);
6020 result =
6021 lookup_account_sid (NULL, group_token.PrimaryGroup,
6022 gname, &glength, NULL, &dlength,
6023 &user_type);
6024 if (result)
6025 w32_add_to_cache (group_token.PrimaryGroup,
6026 egid, gname);
6027 else
6028 {
6029 strcpy (gname, "None");
6030 result = TRUE;
6031 }
6032 }
6033 glength = strlen (gname);
6034 }
6035 }
6036 }
6037 xfree (buf);
6038 }
6039 if (!result)
6040 {
6041 if (!is_windows_9x ())
6042 {
6043 /* We couldn't open the process token, presumably because of
6044 insufficient access rights. Assume this process is run
6045 by the system. */
6046 strcpy (uname, "SYSTEM");
6047 strcpy (gname, "None");
6048 euid = 18; /* SYSTEM */
6049 egid = 513; /* None */
6050 glength = strlen (gname);
6051 ulength = strlen (uname);
6052 }
6053 /* If we are running under Windows 9X, where security calls are
6054 not supported, we assume all processes are run by the current
6055 user. */
6056 else if (GetUserName (uname, &ulength))
6057 {
6058 if (xstrcasecmp ("administrator", uname) == 0)
6059 euid = 0;
6060 else
6061 euid = 123;
6062 egid = euid;
6063 strcpy (gname, "None");
6064 glength = strlen (gname);
6065 ulength = strlen (uname);
6066 }
6067 else
6068 {
6069 euid = 123;
6070 egid = 123;
6071 strcpy (uname, "administrator");
6072 ulength = strlen (uname);
6073 strcpy (gname, "None");
6074 glength = strlen (gname);
6075 }
6076 if (token)
6077 CloseHandle (token);
6078 }
6079
6080 attrs = Fcons (Fcons (Qeuid, make_fixnum_or_float (euid)), attrs);
6081 tem = make_unibyte_string (uname, ulength);
6082 attrs = Fcons (Fcons (Quser,
6083 code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
6084 attrs);
6085 attrs = Fcons (Fcons (Qegid, make_fixnum_or_float (egid)), attrs);
6086 tem = make_unibyte_string (gname, glength);
6087 attrs = Fcons (Fcons (Qgroup,
6088 code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
6089 attrs);
6090
6091 if (global_memory_status_ex (&memstex))
6092 #if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
6093 totphys = memstex.ullTotalPhys / 1024.0;
6094 #else
6095 /* Visual Studio 6 cannot convert an unsigned __int64 type to
6096 double, so we need to do this for it... */
6097 {
6098 DWORD tot_hi = memstex.ullTotalPhys >> 32;
6099 DWORD tot_md = (memstex.ullTotalPhys & 0x00000000ffffffff) >> 10;
6100 DWORD tot_lo = memstex.ullTotalPhys % 1024;
6101
6102 totphys = tot_hi * 4194304.0 + tot_md + tot_lo / 1024.0;
6103 }
6104 #endif /* __GNUC__ || _MSC_VER >= 1300 */
6105 else if (global_memory_status (&memst))
6106 totphys = memst.dwTotalPhys / 1024.0;
6107
6108 if (h_proc
6109 && get_process_memory_info (h_proc, (PROCESS_MEMORY_COUNTERS *)&mem_ex,
6110 sizeof (mem_ex)))
6111 {
6112 SIZE_T rss = mem_ex.WorkingSetSize / 1024;
6113
6114 attrs = Fcons (Fcons (Qmajflt,
6115 make_fixnum_or_float (mem_ex.PageFaultCount)),
6116 attrs);
6117 attrs = Fcons (Fcons (Qvsize,
6118 make_fixnum_or_float (mem_ex.PrivateUsage / 1024)),
6119 attrs);
6120 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (rss)), attrs);
6121 if (totphys)
6122 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
6123 }
6124 else if (h_proc
6125 && get_process_memory_info (h_proc, &mem, sizeof (mem)))
6126 {
6127 SIZE_T rss = mem_ex.WorkingSetSize / 1024;
6128
6129 attrs = Fcons (Fcons (Qmajflt,
6130 make_fixnum_or_float (mem.PageFaultCount)),
6131 attrs);
6132 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (rss)), attrs);
6133 if (totphys)
6134 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
6135 }
6136 else if (h_proc
6137 && get_process_working_set_size (h_proc, &minrss, &maxrss))
6138 {
6139 DWORD rss = maxrss / 1024;
6140
6141 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (maxrss / 1024)), attrs);
6142 if (totphys)
6143 attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
6144 }
6145
6146 if (process_times (h_proc, &ctime, &etime, &stime, &utime, &ttime, &pcpu))
6147 {
6148 attrs = Fcons (Fcons (Qutime, utime), attrs);
6149 attrs = Fcons (Fcons (Qstime, stime), attrs);
6150 attrs = Fcons (Fcons (Qtime, ttime), attrs);
6151 attrs = Fcons (Fcons (Qstart, ctime), attrs);
6152 attrs = Fcons (Fcons (Qetime, etime), attrs);
6153 attrs = Fcons (Fcons (Qpcpu, make_float (pcpu)), attrs);
6154 }
6155
6156 /* FIXME: Retrieve command line by walking the PEB of the process. */
6157
6158 if (h_proc)
6159 CloseHandle (h_proc);
6160 UNGCPRO;
6161 return attrs;
6162 }
6163
6164 \f
6165 /* Wrappers for winsock functions to map between our file descriptors
6166 and winsock's handles; also set h_errno for convenience.
6167
6168 To allow Emacs to run on systems which don't have winsock support
6169 installed, we dynamically link to winsock on startup if present, and
6170 otherwise provide the minimum necessary functionality
6171 (eg. gethostname). */
6172
6173 /* function pointers for relevant socket functions */
6174 int (PASCAL *pfn_WSAStartup) (WORD wVersionRequired, LPWSADATA lpWSAData);
6175 void (PASCAL *pfn_WSASetLastError) (int iError);
6176 int (PASCAL *pfn_WSAGetLastError) (void);
6177 int (PASCAL *pfn_WSAEventSelect) (SOCKET s, HANDLE hEventObject, long lNetworkEvents);
6178 HANDLE (PASCAL *pfn_WSACreateEvent) (void);
6179 int (PASCAL *pfn_WSACloseEvent) (HANDLE hEvent);
6180 int (PASCAL *pfn_socket) (int af, int type, int protocol);
6181 int (PASCAL *pfn_bind) (SOCKET s, const struct sockaddr *addr, int namelen);
6182 int (PASCAL *pfn_connect) (SOCKET s, const struct sockaddr *addr, int namelen);
6183 int (PASCAL *pfn_ioctlsocket) (SOCKET s, long cmd, u_long *argp);
6184 int (PASCAL *pfn_recv) (SOCKET s, char * buf, int len, int flags);
6185 int (PASCAL *pfn_send) (SOCKET s, const char * buf, int len, int flags);
6186 int (PASCAL *pfn_closesocket) (SOCKET s);
6187 int (PASCAL *pfn_shutdown) (SOCKET s, int how);
6188 int (PASCAL *pfn_WSACleanup) (void);
6189
6190 u_short (PASCAL *pfn_htons) (u_short hostshort);
6191 u_short (PASCAL *pfn_ntohs) (u_short netshort);
6192 unsigned long (PASCAL *pfn_inet_addr) (const char * cp);
6193 int (PASCAL *pfn_gethostname) (char * name, int namelen);
6194 struct hostent * (PASCAL *pfn_gethostbyname) (const char * name);
6195 struct servent * (PASCAL *pfn_getservbyname) (const char * name, const char * proto);
6196 int (PASCAL *pfn_getpeername) (SOCKET s, struct sockaddr *addr, int * namelen);
6197 int (PASCAL *pfn_setsockopt) (SOCKET s, int level, int optname,
6198 const char * optval, int optlen);
6199 int (PASCAL *pfn_listen) (SOCKET s, int backlog);
6200 int (PASCAL *pfn_getsockname) (SOCKET s, struct sockaddr * name,
6201 int * namelen);
6202 SOCKET (PASCAL *pfn_accept) (SOCKET s, struct sockaddr * addr, int * addrlen);
6203 int (PASCAL *pfn_recvfrom) (SOCKET s, char * buf, int len, int flags,
6204 struct sockaddr * from, int * fromlen);
6205 int (PASCAL *pfn_sendto) (SOCKET s, const char * buf, int len, int flags,
6206 const struct sockaddr * to, int tolen);
6207
6208 /* SetHandleInformation is only needed to make sockets non-inheritable. */
6209 BOOL (WINAPI *pfn_SetHandleInformation) (HANDLE object, DWORD mask, DWORD flags);
6210 #ifndef HANDLE_FLAG_INHERIT
6211 #define HANDLE_FLAG_INHERIT 1
6212 #endif
6213
6214 HANDLE winsock_lib;
6215 static int winsock_inuse;
6216
6217 BOOL
6218 term_winsock (void)
6219 {
6220 if (winsock_lib != NULL && winsock_inuse == 0)
6221 {
6222 release_listen_threads ();
6223 /* Not sure what would cause WSAENETDOWN, or even if it can happen
6224 after WSAStartup returns successfully, but it seems reasonable
6225 to allow unloading winsock anyway in that case. */
6226 if (pfn_WSACleanup () == 0 ||
6227 pfn_WSAGetLastError () == WSAENETDOWN)
6228 {
6229 if (FreeLibrary (winsock_lib))
6230 winsock_lib = NULL;
6231 return TRUE;
6232 }
6233 }
6234 return FALSE;
6235 }
6236
6237 BOOL
6238 init_winsock (int load_now)
6239 {
6240 WSADATA winsockData;
6241
6242 if (winsock_lib != NULL)
6243 return TRUE;
6244
6245 pfn_SetHandleInformation
6246 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
6247 "SetHandleInformation");
6248
6249 winsock_lib = LoadLibrary ("Ws2_32.dll");
6250
6251 if (winsock_lib != NULL)
6252 {
6253 /* dynamically link to socket functions */
6254
6255 #define LOAD_PROC(fn) \
6256 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
6257 goto fail;
6258
6259 LOAD_PROC (WSAStartup);
6260 LOAD_PROC (WSASetLastError);
6261 LOAD_PROC (WSAGetLastError);
6262 LOAD_PROC (WSAEventSelect);
6263 LOAD_PROC (WSACreateEvent);
6264 LOAD_PROC (WSACloseEvent);
6265 LOAD_PROC (socket);
6266 LOAD_PROC (bind);
6267 LOAD_PROC (connect);
6268 LOAD_PROC (ioctlsocket);
6269 LOAD_PROC (recv);
6270 LOAD_PROC (send);
6271 LOAD_PROC (closesocket);
6272 LOAD_PROC (shutdown);
6273 LOAD_PROC (htons);
6274 LOAD_PROC (ntohs);
6275 LOAD_PROC (inet_addr);
6276 LOAD_PROC (gethostname);
6277 LOAD_PROC (gethostbyname);
6278 LOAD_PROC (getservbyname);
6279 LOAD_PROC (getpeername);
6280 LOAD_PROC (WSACleanup);
6281 LOAD_PROC (setsockopt);
6282 LOAD_PROC (listen);
6283 LOAD_PROC (getsockname);
6284 LOAD_PROC (accept);
6285 LOAD_PROC (recvfrom);
6286 LOAD_PROC (sendto);
6287 #undef LOAD_PROC
6288
6289 /* specify version 1.1 of winsock */
6290 if (pfn_WSAStartup (0x101, &winsockData) == 0)
6291 {
6292 if (winsockData.wVersion != 0x101)
6293 goto fail;
6294
6295 if (!load_now)
6296 {
6297 /* Report that winsock exists and is usable, but leave
6298 socket functions disabled. I am assuming that calling
6299 WSAStartup does not require any network interaction,
6300 and in particular does not cause or require a dial-up
6301 connection to be established. */
6302
6303 pfn_WSACleanup ();
6304 FreeLibrary (winsock_lib);
6305 winsock_lib = NULL;
6306 }
6307 winsock_inuse = 0;
6308 return TRUE;
6309 }
6310
6311 fail:
6312 FreeLibrary (winsock_lib);
6313 winsock_lib = NULL;
6314 }
6315
6316 return FALSE;
6317 }
6318
6319
6320 int h_errno = 0;
6321
6322 /* Function to map winsock error codes to errno codes for those errno
6323 code defined in errno.h (errno values not defined by errno.h are
6324 already in nt/inc/sys/socket.h). */
6325 static void
6326 set_errno (void)
6327 {
6328 int wsa_err;
6329
6330 h_errno = 0;
6331 if (winsock_lib == NULL)
6332 wsa_err = EINVAL;
6333 else
6334 wsa_err = pfn_WSAGetLastError ();
6335
6336 switch (wsa_err)
6337 {
6338 case WSAEACCES: errno = EACCES; break;
6339 case WSAEBADF: errno = EBADF; break;
6340 case WSAEFAULT: errno = EFAULT; break;
6341 case WSAEINTR: errno = EINTR; break;
6342 case WSAEINVAL: errno = EINVAL; break;
6343 case WSAEMFILE: errno = EMFILE; break;
6344 case WSAENAMETOOLONG: errno = ENAMETOOLONG; break;
6345 case WSAENOTEMPTY: errno = ENOTEMPTY; break;
6346 default: errno = wsa_err; break;
6347 }
6348 }
6349
6350 static void
6351 check_errno (void)
6352 {
6353 h_errno = 0;
6354 if (winsock_lib != NULL)
6355 pfn_WSASetLastError (0);
6356 }
6357
6358 /* Extend strerror to handle the winsock-specific error codes. */
6359 struct {
6360 int errnum;
6361 char * msg;
6362 } _wsa_errlist[] = {
6363 {WSAEINTR , "Interrupted function call"},
6364 {WSAEBADF , "Bad file descriptor"},
6365 {WSAEACCES , "Permission denied"},
6366 {WSAEFAULT , "Bad address"},
6367 {WSAEINVAL , "Invalid argument"},
6368 {WSAEMFILE , "Too many open files"},
6369
6370 {WSAEWOULDBLOCK , "Resource temporarily unavailable"},
6371 {WSAEINPROGRESS , "Operation now in progress"},
6372 {WSAEALREADY , "Operation already in progress"},
6373 {WSAENOTSOCK , "Socket operation on non-socket"},
6374 {WSAEDESTADDRREQ , "Destination address required"},
6375 {WSAEMSGSIZE , "Message too long"},
6376 {WSAEPROTOTYPE , "Protocol wrong type for socket"},
6377 {WSAENOPROTOOPT , "Bad protocol option"},
6378 {WSAEPROTONOSUPPORT , "Protocol not supported"},
6379 {WSAESOCKTNOSUPPORT , "Socket type not supported"},
6380 {WSAEOPNOTSUPP , "Operation not supported"},
6381 {WSAEPFNOSUPPORT , "Protocol family not supported"},
6382 {WSAEAFNOSUPPORT , "Address family not supported by protocol family"},
6383 {WSAEADDRINUSE , "Address already in use"},
6384 {WSAEADDRNOTAVAIL , "Cannot assign requested address"},
6385 {WSAENETDOWN , "Network is down"},
6386 {WSAENETUNREACH , "Network is unreachable"},
6387 {WSAENETRESET , "Network dropped connection on reset"},
6388 {WSAECONNABORTED , "Software caused connection abort"},
6389 {WSAECONNRESET , "Connection reset by peer"},
6390 {WSAENOBUFS , "No buffer space available"},
6391 {WSAEISCONN , "Socket is already connected"},
6392 {WSAENOTCONN , "Socket is not connected"},
6393 {WSAESHUTDOWN , "Cannot send after socket shutdown"},
6394 {WSAETOOMANYREFS , "Too many references"}, /* not sure */
6395 {WSAETIMEDOUT , "Connection timed out"},
6396 {WSAECONNREFUSED , "Connection refused"},
6397 {WSAELOOP , "Network loop"}, /* not sure */
6398 {WSAENAMETOOLONG , "Name is too long"},
6399 {WSAEHOSTDOWN , "Host is down"},
6400 {WSAEHOSTUNREACH , "No route to host"},
6401 {WSAENOTEMPTY , "Buffer not empty"}, /* not sure */
6402 {WSAEPROCLIM , "Too many processes"},
6403 {WSAEUSERS , "Too many users"}, /* not sure */
6404 {WSAEDQUOT , "Double quote in host name"}, /* really not sure */
6405 {WSAESTALE , "Data is stale"}, /* not sure */
6406 {WSAEREMOTE , "Remote error"}, /* not sure */
6407
6408 {WSASYSNOTREADY , "Network subsystem is unavailable"},
6409 {WSAVERNOTSUPPORTED , "WINSOCK.DLL version out of range"},
6410 {WSANOTINITIALISED , "Winsock not initialized successfully"},
6411 {WSAEDISCON , "Graceful shutdown in progress"},
6412 #ifdef WSAENOMORE
6413 {WSAENOMORE , "No more operations allowed"}, /* not sure */
6414 {WSAECANCELLED , "Operation cancelled"}, /* not sure */
6415 {WSAEINVALIDPROCTABLE , "Invalid procedure table from service provider"},
6416 {WSAEINVALIDPROVIDER , "Invalid service provider version number"},
6417 {WSAEPROVIDERFAILEDINIT , "Unable to initialize a service provider"},
6418 {WSASYSCALLFAILURE , "System call failure"},
6419 {WSASERVICE_NOT_FOUND , "Service not found"}, /* not sure */
6420 {WSATYPE_NOT_FOUND , "Class type not found"},
6421 {WSA_E_NO_MORE , "No more resources available"}, /* really not sure */
6422 {WSA_E_CANCELLED , "Operation already cancelled"}, /* really not sure */
6423 {WSAEREFUSED , "Operation refused"}, /* not sure */
6424 #endif
6425
6426 {WSAHOST_NOT_FOUND , "Host not found"},
6427 {WSATRY_AGAIN , "Authoritative host not found during name lookup"},
6428 {WSANO_RECOVERY , "Non-recoverable error during name lookup"},
6429 {WSANO_DATA , "Valid name, no data record of requested type"},
6430
6431 {-1, NULL}
6432 };
6433
6434 char *
6435 sys_strerror (int error_no)
6436 {
6437 int i;
6438 static char unknown_msg[40];
6439
6440 if (error_no >= 0 && error_no < sys_nerr)
6441 return sys_errlist[error_no];
6442
6443 for (i = 0; _wsa_errlist[i].errnum >= 0; i++)
6444 if (_wsa_errlist[i].errnum == error_no)
6445 return _wsa_errlist[i].msg;
6446
6447 sprintf (unknown_msg, "Unidentified error: %d", error_no);
6448 return unknown_msg;
6449 }
6450
6451 /* [andrewi 3-May-96] I've had conflicting results using both methods,
6452 but I believe the method of keeping the socket handle separate (and
6453 insuring it is not inheritable) is the correct one. */
6454
6455 #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
6456
6457 static int socket_to_fd (SOCKET s);
6458
6459 int
6460 sys_socket (int af, int type, int protocol)
6461 {
6462 SOCKET s;
6463
6464 if (winsock_lib == NULL)
6465 {
6466 errno = ENETDOWN;
6467 return INVALID_SOCKET;
6468 }
6469
6470 check_errno ();
6471
6472 /* call the real socket function */
6473 s = pfn_socket (af, type, protocol);
6474
6475 if (s != INVALID_SOCKET)
6476 return socket_to_fd (s);
6477
6478 set_errno ();
6479 return -1;
6480 }
6481
6482 /* Convert a SOCKET to a file descriptor. */
6483 static int
6484 socket_to_fd (SOCKET s)
6485 {
6486 int fd;
6487 child_process * cp;
6488
6489 /* Although under NT 3.5 _open_osfhandle will accept a socket
6490 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
6491 that does not work under NT 3.1. However, we can get the same
6492 effect by using a backdoor function to replace an existing
6493 descriptor handle with the one we want. */
6494
6495 /* allocate a file descriptor (with appropriate flags) */
6496 fd = _open ("NUL:", _O_RDWR);
6497 if (fd >= 0)
6498 {
6499 /* Make a non-inheritable copy of the socket handle. Note
6500 that it is possible that sockets aren't actually kernel
6501 handles, which appears to be the case on Windows 9x when
6502 the MS Proxy winsock client is installed. */
6503 {
6504 /* Apparently there is a bug in NT 3.51 with some service
6505 packs, which prevents using DuplicateHandle to make a
6506 socket handle non-inheritable (causes WSACleanup to
6507 hang). The work-around is to use SetHandleInformation
6508 instead if it is available and implemented. */
6509 if (pfn_SetHandleInformation)
6510 {
6511 pfn_SetHandleInformation ((HANDLE) s, HANDLE_FLAG_INHERIT, 0);
6512 }
6513 else
6514 {
6515 HANDLE parent = GetCurrentProcess ();
6516 HANDLE new_s = INVALID_HANDLE_VALUE;
6517
6518 if (DuplicateHandle (parent,
6519 (HANDLE) s,
6520 parent,
6521 &new_s,
6522 0,
6523 FALSE,
6524 DUPLICATE_SAME_ACCESS))
6525 {
6526 /* It is possible that DuplicateHandle succeeds even
6527 though the socket wasn't really a kernel handle,
6528 because a real handle has the same value. So
6529 test whether the new handle really is a socket. */
6530 long nonblocking = 0;
6531 if (pfn_ioctlsocket ((SOCKET) new_s, FIONBIO, &nonblocking) == 0)
6532 {
6533 pfn_closesocket (s);
6534 s = (SOCKET) new_s;
6535 }
6536 else
6537 {
6538 CloseHandle (new_s);
6539 }
6540 }
6541 }
6542 }
6543 eassert (fd < MAXDESC);
6544 fd_info[fd].hnd = (HANDLE) s;
6545
6546 /* set our own internal flags */
6547 fd_info[fd].flags = FILE_SOCKET | FILE_BINARY | FILE_READ | FILE_WRITE;
6548
6549 cp = new_child ();
6550 if (cp)
6551 {
6552 cp->fd = fd;
6553 cp->status = STATUS_READ_ACKNOWLEDGED;
6554
6555 /* attach child_process to fd_info */
6556 if (fd_info[ fd ].cp != NULL)
6557 {
6558 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd));
6559 emacs_abort ();
6560 }
6561
6562 fd_info[ fd ].cp = cp;
6563
6564 /* success! */
6565 winsock_inuse++; /* count open sockets */
6566 return fd;
6567 }
6568
6569 /* clean up */
6570 _close (fd);
6571 }
6572 else
6573 pfn_closesocket (s);
6574 errno = EMFILE;
6575 return -1;
6576 }
6577
6578 int
6579 sys_bind (int s, const struct sockaddr * addr, int namelen)
6580 {
6581 if (winsock_lib == NULL)
6582 {
6583 errno = ENOTSOCK;
6584 return SOCKET_ERROR;
6585 }
6586
6587 check_errno ();
6588 if (fd_info[s].flags & FILE_SOCKET)
6589 {
6590 int rc = pfn_bind (SOCK_HANDLE (s), addr, namelen);
6591 if (rc == SOCKET_ERROR)
6592 set_errno ();
6593 return rc;
6594 }
6595 errno = ENOTSOCK;
6596 return SOCKET_ERROR;
6597 }
6598
6599 int
6600 sys_connect (int s, const struct sockaddr * name, int namelen)
6601 {
6602 if (winsock_lib == NULL)
6603 {
6604 errno = ENOTSOCK;
6605 return SOCKET_ERROR;
6606 }
6607
6608 check_errno ();
6609 if (fd_info[s].flags & FILE_SOCKET)
6610 {
6611 int rc = pfn_connect (SOCK_HANDLE (s), name, namelen);
6612 if (rc == SOCKET_ERROR)
6613 set_errno ();
6614 return rc;
6615 }
6616 errno = ENOTSOCK;
6617 return SOCKET_ERROR;
6618 }
6619
6620 u_short
6621 sys_htons (u_short hostshort)
6622 {
6623 return (winsock_lib != NULL) ?
6624 pfn_htons (hostshort) : hostshort;
6625 }
6626
6627 u_short
6628 sys_ntohs (u_short netshort)
6629 {
6630 return (winsock_lib != NULL) ?
6631 pfn_ntohs (netshort) : netshort;
6632 }
6633
6634 unsigned long
6635 sys_inet_addr (const char * cp)
6636 {
6637 return (winsock_lib != NULL) ?
6638 pfn_inet_addr (cp) : INADDR_NONE;
6639 }
6640
6641 int
6642 sys_gethostname (char * name, int namelen)
6643 {
6644 if (winsock_lib != NULL)
6645 {
6646 int retval;
6647
6648 check_errno ();
6649 retval = pfn_gethostname (name, namelen);
6650 if (retval == SOCKET_ERROR)
6651 set_errno ();
6652 return retval;
6653 }
6654
6655 if (namelen > MAX_COMPUTERNAME_LENGTH)
6656 return !GetComputerName (name, (DWORD *)&namelen);
6657
6658 errno = EFAULT;
6659 return SOCKET_ERROR;
6660 }
6661
6662 struct hostent *
6663 sys_gethostbyname (const char * name)
6664 {
6665 struct hostent * host;
6666 int h_err = h_errno;
6667
6668 if (winsock_lib == NULL)
6669 {
6670 h_errno = NO_RECOVERY;
6671 errno = ENETDOWN;
6672 return NULL;
6673 }
6674
6675 check_errno ();
6676 host = pfn_gethostbyname (name);
6677 if (!host)
6678 {
6679 set_errno ();
6680 h_errno = errno;
6681 }
6682 else
6683 h_errno = h_err;
6684 return host;
6685 }
6686
6687 struct servent *
6688 sys_getservbyname (const char * name, const char * proto)
6689 {
6690 struct servent * serv;
6691
6692 if (winsock_lib == NULL)
6693 {
6694 errno = ENETDOWN;
6695 return NULL;
6696 }
6697
6698 check_errno ();
6699 serv = pfn_getservbyname (name, proto);
6700 if (!serv)
6701 set_errno ();
6702 return serv;
6703 }
6704
6705 int
6706 sys_getpeername (int s, struct sockaddr *addr, int * namelen)
6707 {
6708 if (winsock_lib == NULL)
6709 {
6710 errno = ENETDOWN;
6711 return SOCKET_ERROR;
6712 }
6713
6714 check_errno ();
6715 if (fd_info[s].flags & FILE_SOCKET)
6716 {
6717 int rc = pfn_getpeername (SOCK_HANDLE (s), addr, namelen);
6718 if (rc == SOCKET_ERROR)
6719 set_errno ();
6720 return rc;
6721 }
6722 errno = ENOTSOCK;
6723 return SOCKET_ERROR;
6724 }
6725
6726 int
6727 sys_shutdown (int s, int how)
6728 {
6729 if (winsock_lib == NULL)
6730 {
6731 errno = ENETDOWN;
6732 return SOCKET_ERROR;
6733 }
6734
6735 check_errno ();
6736 if (fd_info[s].flags & FILE_SOCKET)
6737 {
6738 int rc = pfn_shutdown (SOCK_HANDLE (s), how);
6739 if (rc == SOCKET_ERROR)
6740 set_errno ();
6741 return rc;
6742 }
6743 errno = ENOTSOCK;
6744 return SOCKET_ERROR;
6745 }
6746
6747 int
6748 sys_setsockopt (int s, int level, int optname, const void * optval, int optlen)
6749 {
6750 if (winsock_lib == NULL)
6751 {
6752 errno = ENETDOWN;
6753 return SOCKET_ERROR;
6754 }
6755
6756 check_errno ();
6757 if (fd_info[s].flags & FILE_SOCKET)
6758 {
6759 int rc = pfn_setsockopt (SOCK_HANDLE (s), level, optname,
6760 (const char *)optval, optlen);
6761 if (rc == SOCKET_ERROR)
6762 set_errno ();
6763 return rc;
6764 }
6765 errno = ENOTSOCK;
6766 return SOCKET_ERROR;
6767 }
6768
6769 int
6770 sys_listen (int s, int backlog)
6771 {
6772 if (winsock_lib == NULL)
6773 {
6774 errno = ENETDOWN;
6775 return SOCKET_ERROR;
6776 }
6777
6778 check_errno ();
6779 if (fd_info[s].flags & FILE_SOCKET)
6780 {
6781 int rc = pfn_listen (SOCK_HANDLE (s), backlog);
6782 if (rc == SOCKET_ERROR)
6783 set_errno ();
6784 else
6785 fd_info[s].flags |= FILE_LISTEN;
6786 return rc;
6787 }
6788 errno = ENOTSOCK;
6789 return SOCKET_ERROR;
6790 }
6791
6792 int
6793 sys_getsockname (int s, struct sockaddr * name, int * namelen)
6794 {
6795 if (winsock_lib == NULL)
6796 {
6797 errno = ENETDOWN;
6798 return SOCKET_ERROR;
6799 }
6800
6801 check_errno ();
6802 if (fd_info[s].flags & FILE_SOCKET)
6803 {
6804 int rc = pfn_getsockname (SOCK_HANDLE (s), name, namelen);
6805 if (rc == SOCKET_ERROR)
6806 set_errno ();
6807 return rc;
6808 }
6809 errno = ENOTSOCK;
6810 return SOCKET_ERROR;
6811 }
6812
6813 int
6814 sys_accept (int s, struct sockaddr * addr, int * addrlen)
6815 {
6816 if (winsock_lib == NULL)
6817 {
6818 errno = ENETDOWN;
6819 return -1;
6820 }
6821
6822 check_errno ();
6823 if (fd_info[s].flags & FILE_LISTEN)
6824 {
6825 SOCKET t = pfn_accept (SOCK_HANDLE (s), addr, addrlen);
6826 int fd = -1;
6827 if (t == INVALID_SOCKET)
6828 set_errno ();
6829 else
6830 fd = socket_to_fd (t);
6831
6832 if (fd >= 0)
6833 {
6834 fd_info[s].cp->status = STATUS_READ_ACKNOWLEDGED;
6835 ResetEvent (fd_info[s].cp->char_avail);
6836 }
6837 return fd;
6838 }
6839 errno = ENOTSOCK;
6840 return -1;
6841 }
6842
6843 int
6844 sys_recvfrom (int s, char * buf, int len, int flags,
6845 struct sockaddr * from, int * fromlen)
6846 {
6847 if (winsock_lib == NULL)
6848 {
6849 errno = ENETDOWN;
6850 return SOCKET_ERROR;
6851 }
6852
6853 check_errno ();
6854 if (fd_info[s].flags & FILE_SOCKET)
6855 {
6856 int rc = pfn_recvfrom (SOCK_HANDLE (s), buf, len, flags, from, fromlen);
6857 if (rc == SOCKET_ERROR)
6858 set_errno ();
6859 return rc;
6860 }
6861 errno = ENOTSOCK;
6862 return SOCKET_ERROR;
6863 }
6864
6865 int
6866 sys_sendto (int s, const char * buf, int len, int flags,
6867 const struct sockaddr * to, int tolen)
6868 {
6869 if (winsock_lib == NULL)
6870 {
6871 errno = ENETDOWN;
6872 return SOCKET_ERROR;
6873 }
6874
6875 check_errno ();
6876 if (fd_info[s].flags & FILE_SOCKET)
6877 {
6878 int rc = pfn_sendto (SOCK_HANDLE (s), buf, len, flags, to, tolen);
6879 if (rc == SOCKET_ERROR)
6880 set_errno ();
6881 return rc;
6882 }
6883 errno = ENOTSOCK;
6884 return SOCKET_ERROR;
6885 }
6886
6887 /* Windows does not have an fcntl function. Provide an implementation
6888 good enough for Emacs. */
6889 int
6890 fcntl (int s, int cmd, int options)
6891 {
6892 /* In the w32 Emacs port, fcntl (fd, F_DUPFD_CLOEXEC, fd1) is always
6893 invoked in a context where fd1 is closed and all descriptors less
6894 than fd1 are open, so sys_dup is an adequate implementation. */
6895 if (cmd == F_DUPFD_CLOEXEC)
6896 return sys_dup (s);
6897
6898 if (winsock_lib == NULL)
6899 {
6900 errno = ENETDOWN;
6901 return -1;
6902 }
6903
6904 check_errno ();
6905 if (fd_info[s].flags & FILE_SOCKET)
6906 {
6907 if (cmd == F_SETFL && options == O_NONBLOCK)
6908 {
6909 unsigned long nblock = 1;
6910 int rc = pfn_ioctlsocket (SOCK_HANDLE (s), FIONBIO, &nblock);
6911 if (rc == SOCKET_ERROR)
6912 set_errno ();
6913 /* Keep track of the fact that we set this to non-blocking. */
6914 fd_info[s].flags |= FILE_NDELAY;
6915 return rc;
6916 }
6917 else
6918 {
6919 errno = EINVAL;
6920 return SOCKET_ERROR;
6921 }
6922 }
6923 errno = ENOTSOCK;
6924 return SOCKET_ERROR;
6925 }
6926
6927
6928 /* Shadow main io functions: we need to handle pipes and sockets more
6929 intelligently, and implement non-blocking mode as well. */
6930
6931 int
6932 sys_close (int fd)
6933 {
6934 int rc;
6935
6936 if (fd < 0)
6937 {
6938 errno = EBADF;
6939 return -1;
6940 }
6941
6942 if (fd < MAXDESC && fd_info[fd].cp)
6943 {
6944 child_process * cp = fd_info[fd].cp;
6945
6946 fd_info[fd].cp = NULL;
6947
6948 if (CHILD_ACTIVE (cp))
6949 {
6950 /* if last descriptor to active child_process then cleanup */
6951 int i;
6952 for (i = 0; i < MAXDESC; i++)
6953 {
6954 if (i == fd)
6955 continue;
6956 if (fd_info[i].cp == cp)
6957 break;
6958 }
6959 if (i == MAXDESC)
6960 {
6961 if (fd_info[fd].flags & FILE_SOCKET)
6962 {
6963 if (winsock_lib == NULL) emacs_abort ();
6964
6965 pfn_shutdown (SOCK_HANDLE (fd), 2);
6966 rc = pfn_closesocket (SOCK_HANDLE (fd));
6967
6968 winsock_inuse--; /* count open sockets */
6969 }
6970 /* If the process handle is NULL, it's either a socket
6971 or serial connection, or a subprocess that was
6972 already reaped by reap_subprocess, but whose
6973 resources were not yet freed, because its output was
6974 not fully read yet by the time it was reaped. (This
6975 usually happens with async subprocesses whose output
6976 is being read by Emacs.) Otherwise, this process was
6977 not reaped yet, so we set its FD to a negative value
6978 to make sure sys_select will eventually get to
6979 calling the SIGCHLD handler for it, which will then
6980 invoke waitpid and reap_subprocess. */
6981 if (cp->procinfo.hProcess == NULL)
6982 delete_child (cp);
6983 else
6984 cp->fd = -1;
6985 }
6986 }
6987 }
6988
6989 if (fd >= 0 && fd < MAXDESC)
6990 fd_info[fd].flags = 0;
6991
6992 /* Note that sockets do not need special treatment here (at least on
6993 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
6994 closesocket is equivalent to CloseHandle, which is to be expected
6995 because socket handles are fully fledged kernel handles. */
6996 rc = _close (fd);
6997
6998 return rc;
6999 }
7000
7001 int
7002 sys_dup (int fd)
7003 {
7004 int new_fd;
7005
7006 new_fd = _dup (fd);
7007 if (new_fd >= 0 && new_fd < MAXDESC)
7008 {
7009 /* duplicate our internal info as well */
7010 fd_info[new_fd] = fd_info[fd];
7011 }
7012 return new_fd;
7013 }
7014
7015 int
7016 sys_dup2 (int src, int dst)
7017 {
7018 int rc;
7019
7020 if (dst < 0 || dst >= MAXDESC)
7021 {
7022 errno = EBADF;
7023 return -1;
7024 }
7025
7026 /* make sure we close the destination first if it's a pipe or socket */
7027 if (src != dst && fd_info[dst].flags != 0)
7028 sys_close (dst);
7029
7030 rc = _dup2 (src, dst);
7031 if (rc == 0)
7032 {
7033 /* duplicate our internal info as well */
7034 fd_info[dst] = fd_info[src];
7035 }
7036 return rc;
7037 }
7038
7039 int
7040 pipe2 (int * phandles, int pipe2_flags)
7041 {
7042 int rc;
7043 unsigned flags;
7044
7045 eassert (pipe2_flags == O_CLOEXEC);
7046
7047 /* make pipe handles non-inheritable; when we spawn a child, we
7048 replace the relevant handle with an inheritable one. Also put
7049 pipes into binary mode; we will do text mode translation ourselves
7050 if required. */
7051 rc = _pipe (phandles, 0, _O_NOINHERIT | _O_BINARY);
7052
7053 if (rc == 0)
7054 {
7055 /* Protect against overflow, since Windows can open more handles than
7056 our fd_info array has room for. */
7057 if (phandles[0] >= MAXDESC || phandles[1] >= MAXDESC)
7058 {
7059 _close (phandles[0]);
7060 _close (phandles[1]);
7061 errno = EMFILE;
7062 rc = -1;
7063 }
7064 else
7065 {
7066 flags = FILE_PIPE | FILE_READ | FILE_BINARY;
7067 fd_info[phandles[0]].flags = flags;
7068
7069 flags = FILE_PIPE | FILE_WRITE | FILE_BINARY;
7070 fd_info[phandles[1]].flags = flags;
7071 }
7072 }
7073
7074 return rc;
7075 }
7076
7077 /* Function to do blocking read of one byte, needed to implement
7078 select. It is only allowed on communication ports, sockets, or
7079 pipes. */
7080 int
7081 _sys_read_ahead (int fd)
7082 {
7083 child_process * cp;
7084 int rc;
7085
7086 if (fd < 0 || fd >= MAXDESC)
7087 return STATUS_READ_ERROR;
7088
7089 cp = fd_info[fd].cp;
7090
7091 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
7092 return STATUS_READ_ERROR;
7093
7094 if ((fd_info[fd].flags & (FILE_PIPE | FILE_SERIAL | FILE_SOCKET)) == 0
7095 || (fd_info[fd].flags & FILE_READ) == 0)
7096 {
7097 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd));
7098 emacs_abort ();
7099 }
7100
7101 cp->status = STATUS_READ_IN_PROGRESS;
7102
7103 if (fd_info[fd].flags & FILE_PIPE)
7104 {
7105 rc = _read (fd, &cp->chr, sizeof (char));
7106
7107 /* Give subprocess time to buffer some more output for us before
7108 reporting that input is available; we need this because Windows 95
7109 connects DOS programs to pipes by making the pipe appear to be
7110 the normal console stdout - as a result most DOS programs will
7111 write to stdout without buffering, ie. one character at a
7112 time. Even some W32 programs do this - "dir" in a command
7113 shell on NT is very slow if we don't do this. */
7114 if (rc > 0)
7115 {
7116 int wait = w32_pipe_read_delay;
7117
7118 if (wait > 0)
7119 Sleep (wait);
7120 else if (wait < 0)
7121 while (++wait <= 0)
7122 /* Yield remainder of our time slice, effectively giving a
7123 temporary priority boost to the child process. */
7124 Sleep (0);
7125 }
7126 }
7127 else if (fd_info[fd].flags & FILE_SERIAL)
7128 {
7129 HANDLE hnd = fd_info[fd].hnd;
7130 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
7131 COMMTIMEOUTS ct;
7132
7133 /* Configure timeouts for blocking read. */
7134 if (!GetCommTimeouts (hnd, &ct))
7135 {
7136 cp->status = STATUS_READ_ERROR;
7137 return STATUS_READ_ERROR;
7138 }
7139 ct.ReadIntervalTimeout = 0;
7140 ct.ReadTotalTimeoutMultiplier = 0;
7141 ct.ReadTotalTimeoutConstant = 0;
7142 if (!SetCommTimeouts (hnd, &ct))
7143 {
7144 cp->status = STATUS_READ_ERROR;
7145 return STATUS_READ_ERROR;
7146 }
7147
7148 if (!ReadFile (hnd, &cp->chr, sizeof (char), (DWORD*) &rc, ovl))
7149 {
7150 if (GetLastError () != ERROR_IO_PENDING)
7151 {
7152 cp->status = STATUS_READ_ERROR;
7153 return STATUS_READ_ERROR;
7154 }
7155 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
7156 {
7157 cp->status = STATUS_READ_ERROR;
7158 return STATUS_READ_ERROR;
7159 }
7160 }
7161 }
7162 else if (fd_info[fd].flags & FILE_SOCKET)
7163 {
7164 unsigned long nblock = 0;
7165 /* We always want this to block, so temporarily disable NDELAY. */
7166 if (fd_info[fd].flags & FILE_NDELAY)
7167 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
7168
7169 rc = pfn_recv (SOCK_HANDLE (fd), &cp->chr, sizeof (char), 0);
7170
7171 if (fd_info[fd].flags & FILE_NDELAY)
7172 {
7173 nblock = 1;
7174 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
7175 }
7176 }
7177
7178 if (rc == sizeof (char))
7179 cp->status = STATUS_READ_SUCCEEDED;
7180 else
7181 cp->status = STATUS_READ_FAILED;
7182
7183 return cp->status;
7184 }
7185
7186 int
7187 _sys_wait_accept (int fd)
7188 {
7189 HANDLE hEv;
7190 child_process * cp;
7191 int rc;
7192
7193 if (fd < 0 || fd >= MAXDESC)
7194 return STATUS_READ_ERROR;
7195
7196 cp = fd_info[fd].cp;
7197
7198 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
7199 return STATUS_READ_ERROR;
7200
7201 cp->status = STATUS_READ_FAILED;
7202
7203 hEv = pfn_WSACreateEvent ();
7204 rc = pfn_WSAEventSelect (SOCK_HANDLE (fd), hEv, FD_ACCEPT);
7205 if (rc != SOCKET_ERROR)
7206 {
7207 do {
7208 rc = WaitForSingleObject (hEv, 500);
7209 Sleep (5);
7210 } while (rc == WAIT_TIMEOUT
7211 && cp->status != STATUS_READ_ERROR
7212 && cp->char_avail);
7213 pfn_WSAEventSelect (SOCK_HANDLE (fd), NULL, 0);
7214 if (rc == WAIT_OBJECT_0)
7215 cp->status = STATUS_READ_SUCCEEDED;
7216 }
7217 pfn_WSACloseEvent (hEv);
7218
7219 return cp->status;
7220 }
7221
7222 int
7223 sys_read (int fd, char * buffer, unsigned int count)
7224 {
7225 int nchars;
7226 int to_read;
7227 DWORD waiting;
7228 char * orig_buffer = buffer;
7229
7230 if (fd < 0)
7231 {
7232 errno = EBADF;
7233 return -1;
7234 }
7235
7236 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
7237 {
7238 child_process *cp = fd_info[fd].cp;
7239
7240 if ((fd_info[fd].flags & FILE_READ) == 0)
7241 {
7242 errno = EBADF;
7243 return -1;
7244 }
7245
7246 nchars = 0;
7247
7248 /* re-read CR carried over from last read */
7249 if (fd_info[fd].flags & FILE_LAST_CR)
7250 {
7251 if (fd_info[fd].flags & FILE_BINARY) emacs_abort ();
7252 *buffer++ = 0x0d;
7253 count--;
7254 nchars++;
7255 fd_info[fd].flags &= ~FILE_LAST_CR;
7256 }
7257
7258 /* presence of a child_process structure means we are operating in
7259 non-blocking mode - otherwise we just call _read directly.
7260 Note that the child_process structure might be missing because
7261 reap_subprocess has been called; in this case the pipe is
7262 already broken, so calling _read on it is okay. */
7263 if (cp)
7264 {
7265 int current_status = cp->status;
7266
7267 switch (current_status)
7268 {
7269 case STATUS_READ_FAILED:
7270 case STATUS_READ_ERROR:
7271 /* report normal EOF if nothing in buffer */
7272 if (nchars <= 0)
7273 fd_info[fd].flags |= FILE_AT_EOF;
7274 return nchars;
7275
7276 case STATUS_READ_READY:
7277 case STATUS_READ_IN_PROGRESS:
7278 DebPrint (("sys_read called when read is in progress\n"));
7279 errno = EWOULDBLOCK;
7280 return -1;
7281
7282 case STATUS_READ_SUCCEEDED:
7283 /* consume read-ahead char */
7284 *buffer++ = cp->chr;
7285 count--;
7286 nchars++;
7287 cp->status = STATUS_READ_ACKNOWLEDGED;
7288 ResetEvent (cp->char_avail);
7289
7290 case STATUS_READ_ACKNOWLEDGED:
7291 break;
7292
7293 default:
7294 DebPrint (("sys_read: bad status %d\n", current_status));
7295 errno = EBADF;
7296 return -1;
7297 }
7298
7299 if (fd_info[fd].flags & FILE_PIPE)
7300 {
7301 PeekNamedPipe ((HANDLE) _get_osfhandle (fd), NULL, 0, NULL, &waiting, NULL);
7302 to_read = min (waiting, (DWORD) count);
7303
7304 if (to_read > 0)
7305 nchars += _read (fd, buffer, to_read);
7306 }
7307 else if (fd_info[fd].flags & FILE_SERIAL)
7308 {
7309 HANDLE hnd = fd_info[fd].hnd;
7310 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
7311 int rc = 0;
7312 COMMTIMEOUTS ct;
7313
7314 if (count > 0)
7315 {
7316 /* Configure timeouts for non-blocking read. */
7317 if (!GetCommTimeouts (hnd, &ct))
7318 {
7319 errno = EIO;
7320 return -1;
7321 }
7322 ct.ReadIntervalTimeout = MAXDWORD;
7323 ct.ReadTotalTimeoutMultiplier = 0;
7324 ct.ReadTotalTimeoutConstant = 0;
7325 if (!SetCommTimeouts (hnd, &ct))
7326 {
7327 errno = EIO;
7328 return -1;
7329 }
7330
7331 if (!ResetEvent (ovl->hEvent))
7332 {
7333 errno = EIO;
7334 return -1;
7335 }
7336 if (!ReadFile (hnd, buffer, count, (DWORD*) &rc, ovl))
7337 {
7338 if (GetLastError () != ERROR_IO_PENDING)
7339 {
7340 errno = EIO;
7341 return -1;
7342 }
7343 if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
7344 {
7345 errno = EIO;
7346 return -1;
7347 }
7348 }
7349 nchars += rc;
7350 }
7351 }
7352 else /* FILE_SOCKET */
7353 {
7354 if (winsock_lib == NULL) emacs_abort ();
7355
7356 /* do the equivalent of a non-blocking read */
7357 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONREAD, &waiting);
7358 if (waiting == 0 && nchars == 0)
7359 {
7360 errno = EWOULDBLOCK;
7361 return -1;
7362 }
7363
7364 if (waiting)
7365 {
7366 /* always use binary mode for sockets */
7367 int res = pfn_recv (SOCK_HANDLE (fd), buffer, count, 0);
7368 if (res == SOCKET_ERROR)
7369 {
7370 DebPrint (("sys_read.recv failed with error %d on socket %ld\n",
7371 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
7372 set_errno ();
7373 return -1;
7374 }
7375 nchars += res;
7376 }
7377 }
7378 }
7379 else
7380 {
7381 int nread = _read (fd, buffer, count);
7382 if (nread >= 0)
7383 nchars += nread;
7384 else if (nchars == 0)
7385 nchars = nread;
7386 }
7387
7388 if (nchars <= 0)
7389 fd_info[fd].flags |= FILE_AT_EOF;
7390 /* Perform text mode translation if required. */
7391 else if ((fd_info[fd].flags & FILE_BINARY) == 0)
7392 {
7393 nchars = crlf_to_lf (nchars, orig_buffer);
7394 /* If buffer contains only CR, return that. To be absolutely
7395 sure we should attempt to read the next char, but in
7396 practice a CR to be followed by LF would not appear by
7397 itself in the buffer. */
7398 if (nchars > 1 && orig_buffer[nchars - 1] == 0x0d)
7399 {
7400 fd_info[fd].flags |= FILE_LAST_CR;
7401 nchars--;
7402 }
7403 }
7404 }
7405 else
7406 nchars = _read (fd, buffer, count);
7407
7408 return nchars;
7409 }
7410
7411 /* From w32xfns.c */
7412 extern HANDLE interrupt_handle;
7413
7414 /* For now, don't bother with a non-blocking mode */
7415 int
7416 sys_write (int fd, const void * buffer, unsigned int count)
7417 {
7418 int nchars;
7419
7420 if (fd < 0)
7421 {
7422 errno = EBADF;
7423 return -1;
7424 }
7425
7426 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
7427 {
7428 if ((fd_info[fd].flags & FILE_WRITE) == 0)
7429 {
7430 errno = EBADF;
7431 return -1;
7432 }
7433
7434 /* Perform text mode translation if required. */
7435 if ((fd_info[fd].flags & FILE_BINARY) == 0)
7436 {
7437 char * tmpbuf = alloca (count * 2);
7438 unsigned char * src = (void *)buffer;
7439 unsigned char * dst = tmpbuf;
7440 int nbytes = count;
7441
7442 while (1)
7443 {
7444 unsigned char *next;
7445 /* copy next line or remaining bytes */
7446 next = _memccpy (dst, src, '\n', nbytes);
7447 if (next)
7448 {
7449 /* copied one line ending with '\n' */
7450 int copied = next - dst;
7451 nbytes -= copied;
7452 src += copied;
7453 /* insert '\r' before '\n' */
7454 next[-1] = '\r';
7455 next[0] = '\n';
7456 dst = next + 1;
7457 count++;
7458 }
7459 else
7460 /* copied remaining partial line -> now finished */
7461 break;
7462 }
7463 buffer = tmpbuf;
7464 }
7465 }
7466
7467 if (fd < MAXDESC && fd_info[fd].flags & FILE_SERIAL)
7468 {
7469 HANDLE hnd = (HANDLE) _get_osfhandle (fd);
7470 OVERLAPPED *ovl = &fd_info[fd].cp->ovl_write;
7471 HANDLE wait_hnd[2] = { interrupt_handle, ovl->hEvent };
7472 DWORD active = 0;
7473
7474 if (!WriteFile (hnd, buffer, count, (DWORD*) &nchars, ovl))
7475 {
7476 if (GetLastError () != ERROR_IO_PENDING)
7477 {
7478 errno = EIO;
7479 return -1;
7480 }
7481 if (detect_input_pending ())
7482 active = MsgWaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE,
7483 QS_ALLINPUT);
7484 else
7485 active = WaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE);
7486 if (active == WAIT_OBJECT_0)
7487 { /* User pressed C-g, cancel write, then leave. Don't bother
7488 cleaning up as we may only get stuck in buggy drivers. */
7489 PurgeComm (hnd, PURGE_TXABORT | PURGE_TXCLEAR);
7490 CancelIo (hnd);
7491 errno = EIO;
7492 return -1;
7493 }
7494 if (active == WAIT_OBJECT_0 + 1
7495 && !GetOverlappedResult (hnd, ovl, (DWORD*) &nchars, TRUE))
7496 {
7497 errno = EIO;
7498 return -1;
7499 }
7500 }
7501 }
7502 else if (fd < MAXDESC && fd_info[fd].flags & FILE_SOCKET)
7503 {
7504 unsigned long nblock = 0;
7505 if (winsock_lib == NULL) emacs_abort ();
7506
7507 /* TODO: implement select() properly so non-blocking I/O works. */
7508 /* For now, make sure the write blocks. */
7509 if (fd_info[fd].flags & FILE_NDELAY)
7510 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
7511
7512 nchars = pfn_send (SOCK_HANDLE (fd), buffer, count, 0);
7513
7514 /* Set the socket back to non-blocking if it was before,
7515 for other operations that support it. */
7516 if (fd_info[fd].flags & FILE_NDELAY)
7517 {
7518 nblock = 1;
7519 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
7520 }
7521
7522 if (nchars == SOCKET_ERROR)
7523 {
7524 DebPrint (("sys_write.send failed with error %d on socket %ld\n",
7525 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
7526 set_errno ();
7527 }
7528 }
7529 else
7530 {
7531 /* Some networked filesystems don't like too large writes, so
7532 break them into smaller chunks. See the Comments section of
7533 the MSDN documentation of WriteFile for details behind the
7534 choice of the value of CHUNK below. See also the thread
7535 http://thread.gmane.org/gmane.comp.version-control.git/145294
7536 in the git mailing list. */
7537 const unsigned char *p = buffer;
7538 const unsigned chunk = 30 * 1024 * 1024;
7539
7540 nchars = 0;
7541 while (count > 0)
7542 {
7543 unsigned this_chunk = count < chunk ? count : chunk;
7544 int n = _write (fd, p, this_chunk);
7545
7546 nchars += n;
7547 if (n < 0)
7548 {
7549 nchars = n;
7550 break;
7551 }
7552 else if (n < this_chunk)
7553 break;
7554 count -= n;
7555 p += n;
7556 }
7557 }
7558
7559 return nchars;
7560 }
7561
7562 \f
7563 /* Emulation of SIOCGIFCONF and getifaddrs, see process.c. */
7564
7565 extern Lisp_Object conv_sockaddr_to_lisp (struct sockaddr *, int);
7566
7567 /* Return information about network interface IFNAME, or about all
7568 interfaces (if IFNAME is nil). */
7569 static Lisp_Object
7570 network_interface_get_info (Lisp_Object ifname)
7571 {
7572 ULONG ainfo_len = sizeof (IP_ADAPTER_INFO);
7573 IP_ADAPTER_INFO *adapter, *ainfo = xmalloc (ainfo_len);
7574 DWORD retval = get_adapters_info (ainfo, &ainfo_len);
7575 Lisp_Object res = Qnil;
7576
7577 if (retval == ERROR_BUFFER_OVERFLOW)
7578 {
7579 ainfo = xrealloc (ainfo, ainfo_len);
7580 retval = get_adapters_info (ainfo, &ainfo_len);
7581 }
7582
7583 if (retval == ERROR_SUCCESS)
7584 {
7585 int eth_count = 0, tr_count = 0, fddi_count = 0, ppp_count = 0;
7586 int sl_count = 0, wlan_count = 0, lo_count = 0, ifx_count = 0;
7587 int if_num;
7588 struct sockaddr_in sa;
7589
7590 /* For the below, we need some winsock functions, so make sure
7591 the winsock DLL is loaded. If we cannot successfully load
7592 it, they will have no use of the information we provide,
7593 anyway, so punt. */
7594 if (!winsock_lib && !init_winsock (1))
7595 goto done;
7596
7597 for (adapter = ainfo; adapter; adapter = adapter->Next)
7598 {
7599 char namebuf[MAX_ADAPTER_NAME_LENGTH + 4];
7600 u_long ip_addr;
7601 /* Present Unix-compatible interface names, instead of the
7602 Windows names, which are really GUIDs not readable by
7603 humans. */
7604 static const char *ifmt[] = {
7605 "eth%d", "tr%d", "fddi%d", "ppp%d", "sl%d", "wlan%d",
7606 "lo", "ifx%d"
7607 };
7608 enum {
7609 NONE = -1,
7610 ETHERNET = 0,
7611 TOKENRING = 1,
7612 FDDI = 2,
7613 PPP = 3,
7614 SLIP = 4,
7615 WLAN = 5,
7616 LOOPBACK = 6,
7617 OTHER_IF = 7
7618 } ifmt_idx;
7619
7620 switch (adapter->Type)
7621 {
7622 case MIB_IF_TYPE_ETHERNET:
7623 /* Windows before Vista reports wireless adapters as
7624 Ethernet. Work around by looking at the Description
7625 string. */
7626 if (strstr (adapter->Description, "Wireless "))
7627 {
7628 ifmt_idx = WLAN;
7629 if_num = wlan_count++;
7630 }
7631 else
7632 {
7633 ifmt_idx = ETHERNET;
7634 if_num = eth_count++;
7635 }
7636 break;
7637 case MIB_IF_TYPE_TOKENRING:
7638 ifmt_idx = TOKENRING;
7639 if_num = tr_count++;
7640 break;
7641 case MIB_IF_TYPE_FDDI:
7642 ifmt_idx = FDDI;
7643 if_num = fddi_count++;
7644 break;
7645 case MIB_IF_TYPE_PPP:
7646 ifmt_idx = PPP;
7647 if_num = ppp_count++;
7648 break;
7649 case MIB_IF_TYPE_SLIP:
7650 ifmt_idx = SLIP;
7651 if_num = sl_count++;
7652 break;
7653 case IF_TYPE_IEEE80211:
7654 ifmt_idx = WLAN;
7655 if_num = wlan_count++;
7656 break;
7657 case MIB_IF_TYPE_LOOPBACK:
7658 if (lo_count < 0)
7659 {
7660 ifmt_idx = LOOPBACK;
7661 if_num = lo_count++;
7662 }
7663 else
7664 ifmt_idx = NONE;
7665 break;
7666 default:
7667 ifmt_idx = OTHER_IF;
7668 if_num = ifx_count++;
7669 break;
7670 }
7671 if (ifmt_idx == NONE)
7672 continue;
7673 sprintf (namebuf, ifmt[ifmt_idx], if_num);
7674
7675 sa.sin_family = AF_INET;
7676 ip_addr = sys_inet_addr (adapter->IpAddressList.IpAddress.String);
7677 if (ip_addr == INADDR_NONE)
7678 {
7679 /* Bogus address, skip this interface. */
7680 continue;
7681 }
7682 sa.sin_addr.s_addr = ip_addr;
7683 sa.sin_port = 0;
7684 if (NILP (ifname))
7685 res = Fcons (Fcons (build_string (namebuf),
7686 conv_sockaddr_to_lisp ((struct sockaddr*) &sa,
7687 sizeof (struct sockaddr))),
7688 res);
7689 else if (strcmp (namebuf, SSDATA (ifname)) == 0)
7690 {
7691 Lisp_Object hwaddr = Fmake_vector (make_number (6), Qnil);
7692 register struct Lisp_Vector *p = XVECTOR (hwaddr);
7693 Lisp_Object flags = Qnil;
7694 int n;
7695 u_long net_mask;
7696
7697 /* Flags. We guess most of them by type, since the
7698 Windows flags are different and hard to get by. */
7699 flags = Fcons (intern ("up"), flags);
7700 if (ifmt_idx == ETHERNET || ifmt_idx == WLAN)
7701 {
7702 flags = Fcons (intern ("broadcast"), flags);
7703 flags = Fcons (intern ("multicast"), flags);
7704 }
7705 flags = Fcons (intern ("running"), flags);
7706 if (ifmt_idx == PPP)
7707 {
7708 flags = Fcons (intern ("pointopoint"), flags);
7709 flags = Fcons (intern ("noarp"), flags);
7710 }
7711 if (adapter->HaveWins)
7712 flags = Fcons (intern ("WINS"), flags);
7713 if (adapter->DhcpEnabled)
7714 flags = Fcons (intern ("dynamic"), flags);
7715
7716 res = Fcons (flags, res);
7717
7718 /* Hardware address and its family. */
7719 for (n = 0; n < adapter->AddressLength; n++)
7720 p->u.contents[n] = make_number ((int) adapter->Address[n]);
7721 /* Windows does not support AF_LINK or AF_PACKET family
7722 of addresses. Use an arbitrary family number that is
7723 identical to what GNU/Linux returns. */
7724 res = Fcons (Fcons (make_number (1), hwaddr), res);
7725
7726 /* Network mask. */
7727 sa.sin_family = AF_INET;
7728 net_mask = sys_inet_addr (adapter->IpAddressList.IpMask.String);
7729 if (net_mask != INADDR_NONE)
7730 {
7731 sa.sin_addr.s_addr = net_mask;
7732 sa.sin_port = 0;
7733 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
7734 sizeof (struct sockaddr)),
7735 res);
7736 }
7737 else
7738 res = Fcons (Qnil, res);
7739
7740 sa.sin_family = AF_INET;
7741 if (ip_addr != INADDR_NONE)
7742 {
7743 /* Broadcast address is only reported by
7744 GetAdaptersAddresses, which is of limited
7745 availability. Generate it on our own. */
7746 u_long bcast_addr = (ip_addr & net_mask) | ~net_mask;
7747
7748 sa.sin_addr.s_addr = bcast_addr;
7749 sa.sin_port = 0;
7750 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
7751 sizeof (struct sockaddr)),
7752 res);
7753
7754 /* IP address. */
7755 sa.sin_addr.s_addr = ip_addr;
7756 sa.sin_port = 0;
7757 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
7758 sizeof (struct sockaddr)),
7759 res);
7760 }
7761 else
7762 res = Fcons (Qnil, Fcons (Qnil, res));
7763 }
7764 }
7765 /* GetAdaptersInfo is documented to not report loopback
7766 interfaces, so we generate one out of thin air. */
7767 if (!lo_count)
7768 {
7769 sa.sin_family = AF_INET;
7770 sa.sin_port = 0;
7771 if (NILP (ifname))
7772 {
7773 sa.sin_addr.s_addr = sys_inet_addr ("127.0.0.1");
7774 res = Fcons (Fcons (build_string ("lo"),
7775 conv_sockaddr_to_lisp ((struct sockaddr*) &sa,
7776 sizeof (struct sockaddr))),
7777 res);
7778 }
7779 else if (strcmp (SSDATA (ifname), "lo") == 0)
7780 {
7781 res = Fcons (Fcons (intern ("running"),
7782 Fcons (intern ("loopback"),
7783 Fcons (intern ("up"), Qnil))), Qnil);
7784 /* 772 is what 3 different GNU/Linux systems report for
7785 the loopback interface. */
7786 res = Fcons (Fcons (make_number (772),
7787 Fmake_vector (make_number (6),
7788 make_number (0))),
7789 res);
7790 sa.sin_addr.s_addr = sys_inet_addr ("255.0.0.0");
7791 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
7792 sizeof (struct sockaddr)),
7793 res);
7794 sa.sin_addr.s_addr = sys_inet_addr ("0.0.0.0");
7795 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
7796 sizeof (struct sockaddr)),
7797 res);
7798 sa.sin_addr.s_addr = sys_inet_addr ("127.0.0.1");
7799 res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
7800 sizeof (struct sockaddr)),
7801 res);
7802 }
7803
7804 }
7805 }
7806
7807 done:
7808 xfree (ainfo);
7809 return res;
7810 }
7811
7812 Lisp_Object
7813 network_interface_list (void)
7814 {
7815 return network_interface_get_info (Qnil);
7816 }
7817
7818 Lisp_Object
7819 network_interface_info (Lisp_Object ifname)
7820 {
7821 return network_interface_get_info (ifname);
7822 }
7823
7824 \f
7825 /* The Windows CRT functions are "optimized for speed", so they don't
7826 check for timezone and DST changes if they were last called less
7827 than 1 minute ago (see http://support.microsoft.com/kb/821231). So
7828 all Emacs features that repeatedly call time functions (e.g.,
7829 display-time) are in real danger of missing timezone and DST
7830 changes. Calling tzset before each localtime call fixes that. */
7831 struct tm *
7832 sys_localtime (const time_t *t)
7833 {
7834 tzset ();
7835 return localtime (t);
7836 }
7837
7838
7839 \f
7840 /* Try loading LIBRARY_ID from the file(s) specified in
7841 Vdynamic_library_alist. If the library is loaded successfully,
7842 return the handle of the DLL, and record the filename in the
7843 property :loaded-from of LIBRARY_ID. If the library could not be
7844 found, or when it was already loaded (because the handle is not
7845 recorded anywhere, and so is lost after use), return NULL.
7846
7847 We could also save the handle in :loaded-from, but currently
7848 there's no use case for it. */
7849 HMODULE
7850 w32_delayed_load (Lisp_Object library_id)
7851 {
7852 HMODULE library_dll = NULL;
7853
7854 CHECK_SYMBOL (library_id);
7855
7856 if (CONSP (Vdynamic_library_alist)
7857 && NILP (Fassq (library_id, Vlibrary_cache)))
7858 {
7859 Lisp_Object found = Qnil;
7860 Lisp_Object dlls = Fassq (library_id, Vdynamic_library_alist);
7861
7862 if (CONSP (dlls))
7863 for (dlls = XCDR (dlls); CONSP (dlls); dlls = XCDR (dlls))
7864 {
7865 CHECK_STRING_CAR (dlls);
7866 if ((library_dll = LoadLibrary (SDATA (XCAR (dlls)))))
7867 {
7868 char name[MAX_PATH];
7869 DWORD len;
7870
7871 len = GetModuleFileNameA (library_dll, name, sizeof (name));
7872 found = Fcons (XCAR (dlls),
7873 (len > 0)
7874 /* Possibly truncated */
7875 ? make_specified_string (name, -1, len, 1)
7876 : Qnil);
7877 break;
7878 }
7879 }
7880
7881 Fput (library_id, QCloaded_from, found);
7882 }
7883
7884 return library_dll;
7885 }
7886
7887 \f
7888 void
7889 check_windows_init_file (void)
7890 {
7891 /* A common indication that Emacs is not installed properly is when
7892 it cannot find the Windows installation file. If this file does
7893 not exist in the expected place, tell the user. */
7894
7895 if (!noninteractive && !inhibit_window_system
7896 /* Vload_path is not yet initialized when we are loading
7897 loadup.el. */
7898 && NILP (Vpurify_flag))
7899 {
7900 Lisp_Object init_file;
7901 int fd;
7902
7903 init_file = build_string ("term/w32-win");
7904 fd = openp (Vload_path, init_file, Fget_load_suffixes (), NULL, Qnil);
7905 if (fd < 0)
7906 {
7907 Lisp_Object load_path_print = Fprin1_to_string (Vload_path, Qnil);
7908 char *init_file_name = SDATA (init_file);
7909 char *load_path = SDATA (load_path_print);
7910 char *buffer = alloca (1024
7911 + strlen (init_file_name)
7912 + strlen (load_path));
7913
7914 sprintf (buffer,
7915 "The Emacs Windows initialization file \"%s.el\" "
7916 "could not be found in your Emacs installation. "
7917 "Emacs checked the following directories for this file:\n"
7918 "\n%s\n\n"
7919 "When Emacs cannot find this file, it usually means that it "
7920 "was not installed properly, or its distribution file was "
7921 "not unpacked properly.\nSee the README.W32 file in the "
7922 "top-level Emacs directory for more information.",
7923 init_file_name, load_path);
7924 MessageBox (NULL,
7925 buffer,
7926 "Emacs Abort Dialog",
7927 MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
7928 /* Use the low-level system abort. */
7929 abort ();
7930 }
7931 else
7932 {
7933 _close (fd);
7934 }
7935 }
7936 }
7937
7938 void
7939 term_ntproc (int ignored)
7940 {
7941 (void)ignored;
7942
7943 term_timers ();
7944
7945 /* shutdown the socket interface if necessary */
7946 term_winsock ();
7947
7948 term_w32select ();
7949 }
7950
7951 void
7952 init_ntproc (int dumping)
7953 {
7954 sigset_t initial_mask = 0;
7955
7956 /* Initialize the socket interface now if available and requested by
7957 the user by defining PRELOAD_WINSOCK; otherwise loading will be
7958 delayed until open-network-stream is called (w32-has-winsock can
7959 also be used to dynamically load or reload winsock).
7960
7961 Conveniently, init_environment is called before us, so
7962 PRELOAD_WINSOCK can be set in the registry. */
7963
7964 /* Always initialize this correctly. */
7965 winsock_lib = NULL;
7966
7967 if (getenv ("PRELOAD_WINSOCK") != NULL)
7968 init_winsock (TRUE);
7969
7970 /* Initial preparation for subprocess support: replace our standard
7971 handles with non-inheritable versions. */
7972 {
7973 HANDLE parent;
7974 HANDLE stdin_save = INVALID_HANDLE_VALUE;
7975 HANDLE stdout_save = INVALID_HANDLE_VALUE;
7976 HANDLE stderr_save = INVALID_HANDLE_VALUE;
7977
7978 parent = GetCurrentProcess ();
7979
7980 /* ignore errors when duplicating and closing; typically the
7981 handles will be invalid when running as a gui program. */
7982 DuplicateHandle (parent,
7983 GetStdHandle (STD_INPUT_HANDLE),
7984 parent,
7985 &stdin_save,
7986 0,
7987 FALSE,
7988 DUPLICATE_SAME_ACCESS);
7989
7990 DuplicateHandle (parent,
7991 GetStdHandle (STD_OUTPUT_HANDLE),
7992 parent,
7993 &stdout_save,
7994 0,
7995 FALSE,
7996 DUPLICATE_SAME_ACCESS);
7997
7998 DuplicateHandle (parent,
7999 GetStdHandle (STD_ERROR_HANDLE),
8000 parent,
8001 &stderr_save,
8002 0,
8003 FALSE,
8004 DUPLICATE_SAME_ACCESS);
8005
8006 fclose (stdin);
8007 fclose (stdout);
8008 fclose (stderr);
8009
8010 if (stdin_save != INVALID_HANDLE_VALUE)
8011 _open_osfhandle ((intptr_t) stdin_save, O_TEXT);
8012 else
8013 _open ("nul", O_TEXT | O_NOINHERIT | O_RDONLY);
8014 _fdopen (0, "r");
8015
8016 if (stdout_save != INVALID_HANDLE_VALUE)
8017 _open_osfhandle ((intptr_t) stdout_save, O_TEXT);
8018 else
8019 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
8020 _fdopen (1, "w");
8021
8022 if (stderr_save != INVALID_HANDLE_VALUE)
8023 _open_osfhandle ((intptr_t) stderr_save, O_TEXT);
8024 else
8025 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
8026 _fdopen (2, "w");
8027 }
8028
8029 /* unfortunately, atexit depends on implementation of malloc */
8030 /* atexit (term_ntproc); */
8031 if (!dumping)
8032 {
8033 /* Make sure we start with all signals unblocked. */
8034 sigprocmask (SIG_SETMASK, &initial_mask, NULL);
8035 signal (SIGABRT, term_ntproc);
8036 }
8037 init_timers ();
8038
8039 /* determine which drives are fixed, for GetCachedVolumeInformation */
8040 {
8041 /* GetDriveType must have trailing backslash. */
8042 char drive[] = "A:\\";
8043
8044 /* Loop over all possible drive letters */
8045 while (*drive <= 'Z')
8046 {
8047 /* Record if this drive letter refers to a fixed drive. */
8048 fixed_drives[DRIVE_INDEX (*drive)] =
8049 (GetDriveType (drive) == DRIVE_FIXED);
8050
8051 (*drive)++;
8052 }
8053
8054 /* Reset the volume info cache. */
8055 volume_cache = NULL;
8056 }
8057 }
8058
8059 /*
8060 shutdown_handler ensures that buffers' autosave files are
8061 up to date when the user logs off, or the system shuts down.
8062 */
8063 static BOOL WINAPI
8064 shutdown_handler (DWORD type)
8065 {
8066 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
8067 if (type == CTRL_CLOSE_EVENT /* User closes console window. */
8068 || type == CTRL_LOGOFF_EVENT /* User logs off. */
8069 || type == CTRL_SHUTDOWN_EVENT) /* User shutsdown. */
8070 {
8071 /* Shut down cleanly, making sure autosave files are up to date. */
8072 shut_down_emacs (0, Qnil);
8073 }
8074
8075 /* Allow other handlers to handle this signal. */
8076 return FALSE;
8077 }
8078
8079 /*
8080 globals_of_w32 is used to initialize those global variables that
8081 must always be initialized on startup even when the global variable
8082 initialized is non zero (see the function main in emacs.c).
8083 */
8084 void
8085 globals_of_w32 (void)
8086 {
8087 HMODULE kernel32 = GetModuleHandle ("kernel32.dll");
8088
8089 get_process_times_fn = (GetProcessTimes_Proc)
8090 GetProcAddress (kernel32, "GetProcessTimes");
8091
8092 DEFSYM (QCloaded_from, ":loaded-from");
8093
8094 g_b_init_is_windows_9x = 0;
8095 g_b_init_open_process_token = 0;
8096 g_b_init_get_token_information = 0;
8097 g_b_init_lookup_account_sid = 0;
8098 g_b_init_get_sid_sub_authority = 0;
8099 g_b_init_get_sid_sub_authority_count = 0;
8100 g_b_init_get_security_info = 0;
8101 g_b_init_get_file_security = 0;
8102 g_b_init_get_security_descriptor_owner = 0;
8103 g_b_init_get_security_descriptor_group = 0;
8104 g_b_init_is_valid_sid = 0;
8105 g_b_init_create_toolhelp32_snapshot = 0;
8106 g_b_init_process32_first = 0;
8107 g_b_init_process32_next = 0;
8108 g_b_init_open_thread_token = 0;
8109 g_b_init_impersonate_self = 0;
8110 g_b_init_revert_to_self = 0;
8111 g_b_init_get_process_memory_info = 0;
8112 g_b_init_get_process_working_set_size = 0;
8113 g_b_init_global_memory_status = 0;
8114 g_b_init_global_memory_status_ex = 0;
8115 g_b_init_equal_sid = 0;
8116 g_b_init_copy_sid = 0;
8117 g_b_init_get_length_sid = 0;
8118 g_b_init_get_native_system_info = 0;
8119 g_b_init_get_system_times = 0;
8120 g_b_init_create_symbolic_link = 0;
8121 g_b_init_get_security_descriptor_dacl = 0;
8122 g_b_init_convert_sd_to_sddl = 0;
8123 g_b_init_convert_sddl_to_sd = 0;
8124 g_b_init_is_valid_security_descriptor = 0;
8125 g_b_init_set_file_security = 0;
8126 g_b_init_get_adapters_info = 0;
8127 num_of_processors = 0;
8128 /* The following sets a handler for shutdown notifications for
8129 console apps. This actually applies to Emacs in both console and
8130 GUI modes, since we had to fool windows into thinking emacs is a
8131 console application to get console mode to work. */
8132 SetConsoleCtrlHandler (shutdown_handler, TRUE);
8133
8134 /* "None" is the default group name on standalone workstations. */
8135 strcpy (dflt_group_name, "None");
8136
8137 /* Reset, in case it has some value inherited from dump time. */
8138 w32_stat_get_owner_group = 0;
8139
8140 /* If w32_unicode_filenames is non-zero, we will be using Unicode
8141 (a.k.a. "wide") APIs to invoke functions that accept file
8142 names. */
8143 if (is_windows_9x ())
8144 w32_unicode_filenames = 0;
8145 else
8146 w32_unicode_filenames = 1;
8147 }
8148
8149 /* For make-serial-process */
8150 int
8151 serial_open (Lisp_Object port_obj)
8152 {
8153 char *port = SSDATA (port_obj);
8154 HANDLE hnd;
8155 child_process *cp;
8156 int fd = -1;
8157
8158 hnd = CreateFile (port, GENERIC_READ | GENERIC_WRITE, 0, 0,
8159 OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
8160 if (hnd == INVALID_HANDLE_VALUE)
8161 error ("Could not open %s", port);
8162 fd = (int) _open_osfhandle ((intptr_t) hnd, 0);
8163 if (fd == -1)
8164 error ("Could not open %s", port);
8165
8166 cp = new_child ();
8167 if (!cp)
8168 error ("Could not create child process");
8169 cp->fd = fd;
8170 cp->status = STATUS_READ_ACKNOWLEDGED;
8171 fd_info[ fd ].hnd = hnd;
8172 fd_info[ fd ].flags |=
8173 FILE_READ | FILE_WRITE | FILE_BINARY | FILE_SERIAL;
8174 if (fd_info[ fd ].cp != NULL)
8175 {
8176 error ("fd_info[fd = %d] is already in use", fd);
8177 }
8178 fd_info[ fd ].cp = cp;
8179 cp->ovl_read.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
8180 if (cp->ovl_read.hEvent == NULL)
8181 error ("Could not create read event");
8182 cp->ovl_write.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
8183 if (cp->ovl_write.hEvent == NULL)
8184 error ("Could not create write event");
8185
8186 return fd;
8187 }
8188
8189 /* For serial-process-configure */
8190 void
8191 serial_configure (struct Lisp_Process *p, Lisp_Object contact)
8192 {
8193 Lisp_Object childp2 = Qnil;
8194 Lisp_Object tem = Qnil;
8195 HANDLE hnd;
8196 DCB dcb;
8197 COMMTIMEOUTS ct;
8198 char summary[4] = "???"; /* This usually becomes "8N1". */
8199
8200 if ((fd_info[ p->outfd ].flags & FILE_SERIAL) == 0)
8201 error ("Not a serial process");
8202 hnd = fd_info[ p->outfd ].hnd;
8203
8204 childp2 = Fcopy_sequence (p->childp);
8205
8206 /* Initialize timeouts for blocking read and blocking write. */
8207 if (!GetCommTimeouts (hnd, &ct))
8208 error ("GetCommTimeouts() failed");
8209 ct.ReadIntervalTimeout = 0;
8210 ct.ReadTotalTimeoutMultiplier = 0;
8211 ct.ReadTotalTimeoutConstant = 0;
8212 ct.WriteTotalTimeoutMultiplier = 0;
8213 ct.WriteTotalTimeoutConstant = 0;
8214 if (!SetCommTimeouts (hnd, &ct))
8215 error ("SetCommTimeouts() failed");
8216 /* Read port attributes and prepare default configuration. */
8217 memset (&dcb, 0, sizeof (dcb));
8218 dcb.DCBlength = sizeof (DCB);
8219 if (!GetCommState (hnd, &dcb))
8220 error ("GetCommState() failed");
8221 dcb.fBinary = TRUE;
8222 dcb.fNull = FALSE;
8223 dcb.fAbortOnError = FALSE;
8224 /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
8225 dcb.ErrorChar = 0;
8226 dcb.EofChar = 0;
8227 dcb.EvtChar = 0;
8228
8229 /* Configure speed. */
8230 if (!NILP (Fplist_member (contact, QCspeed)))
8231 tem = Fplist_get (contact, QCspeed);
8232 else
8233 tem = Fplist_get (p->childp, QCspeed);
8234 CHECK_NUMBER (tem);
8235 dcb.BaudRate = XINT (tem);
8236 childp2 = Fplist_put (childp2, QCspeed, tem);
8237
8238 /* Configure bytesize. */
8239 if (!NILP (Fplist_member (contact, QCbytesize)))
8240 tem = Fplist_get (contact, QCbytesize);
8241 else
8242 tem = Fplist_get (p->childp, QCbytesize);
8243 if (NILP (tem))
8244 tem = make_number (8);
8245 CHECK_NUMBER (tem);
8246 if (XINT (tem) != 7 && XINT (tem) != 8)
8247 error (":bytesize must be nil (8), 7, or 8");
8248 dcb.ByteSize = XINT (tem);
8249 summary[0] = XINT (tem) + '0';
8250 childp2 = Fplist_put (childp2, QCbytesize, tem);
8251
8252 /* Configure parity. */
8253 if (!NILP (Fplist_member (contact, QCparity)))
8254 tem = Fplist_get (contact, QCparity);
8255 else
8256 tem = Fplist_get (p->childp, QCparity);
8257 if (!NILP (tem) && !EQ (tem, Qeven) && !EQ (tem, Qodd))
8258 error (":parity must be nil (no parity), `even', or `odd'");
8259 dcb.fParity = FALSE;
8260 dcb.Parity = NOPARITY;
8261 dcb.fErrorChar = FALSE;
8262 if (NILP (tem))
8263 {
8264 summary[1] = 'N';
8265 }
8266 else if (EQ (tem, Qeven))
8267 {
8268 summary[1] = 'E';
8269 dcb.fParity = TRUE;
8270 dcb.Parity = EVENPARITY;
8271 dcb.fErrorChar = TRUE;
8272 }
8273 else if (EQ (tem, Qodd))
8274 {
8275 summary[1] = 'O';
8276 dcb.fParity = TRUE;
8277 dcb.Parity = ODDPARITY;
8278 dcb.fErrorChar = TRUE;
8279 }
8280 childp2 = Fplist_put (childp2, QCparity, tem);
8281
8282 /* Configure stopbits. */
8283 if (!NILP (Fplist_member (contact, QCstopbits)))
8284 tem = Fplist_get (contact, QCstopbits);
8285 else
8286 tem = Fplist_get (p->childp, QCstopbits);
8287 if (NILP (tem))
8288 tem = make_number (1);
8289 CHECK_NUMBER (tem);
8290 if (XINT (tem) != 1 && XINT (tem) != 2)
8291 error (":stopbits must be nil (1 stopbit), 1, or 2");
8292 summary[2] = XINT (tem) + '0';
8293 if (XINT (tem) == 1)
8294 dcb.StopBits = ONESTOPBIT;
8295 else if (XINT (tem) == 2)
8296 dcb.StopBits = TWOSTOPBITS;
8297 childp2 = Fplist_put (childp2, QCstopbits, tem);
8298
8299 /* Configure flowcontrol. */
8300 if (!NILP (Fplist_member (contact, QCflowcontrol)))
8301 tem = Fplist_get (contact, QCflowcontrol);
8302 else
8303 tem = Fplist_get (p->childp, QCflowcontrol);
8304 if (!NILP (tem) && !EQ (tem, Qhw) && !EQ (tem, Qsw))
8305 error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
8306 dcb.fOutxCtsFlow = FALSE;
8307 dcb.fOutxDsrFlow = FALSE;
8308 dcb.fDtrControl = DTR_CONTROL_DISABLE;
8309 dcb.fDsrSensitivity = FALSE;
8310 dcb.fTXContinueOnXoff = FALSE;
8311 dcb.fOutX = FALSE;
8312 dcb.fInX = FALSE;
8313 dcb.fRtsControl = RTS_CONTROL_DISABLE;
8314 dcb.XonChar = 17; /* Control-Q */
8315 dcb.XoffChar = 19; /* Control-S */
8316 if (NILP (tem))
8317 {
8318 /* Already configured. */
8319 }
8320 else if (EQ (tem, Qhw))
8321 {
8322 dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
8323 dcb.fOutxCtsFlow = TRUE;
8324 }
8325 else if (EQ (tem, Qsw))
8326 {
8327 dcb.fOutX = TRUE;
8328 dcb.fInX = TRUE;
8329 }
8330 childp2 = Fplist_put (childp2, QCflowcontrol, tem);
8331
8332 /* Activate configuration. */
8333 if (!SetCommState (hnd, &dcb))
8334 error ("SetCommState() failed");
8335
8336 childp2 = Fplist_put (childp2, QCsummary, build_string (summary));
8337 pset_childp (p, childp2);
8338 }
8339
8340 #ifdef HAVE_GNUTLS
8341
8342 ssize_t
8343 emacs_gnutls_pull (gnutls_transport_ptr_t p, void* buf, size_t sz)
8344 {
8345 int n, err;
8346 SELECT_TYPE fdset;
8347 struct timespec timeout;
8348 struct Lisp_Process *process = (struct Lisp_Process *)p;
8349 int fd = process->infd;
8350
8351 n = sys_read (fd, (char*)buf, sz);
8352
8353 if (n >= 0)
8354 return n;
8355
8356 err = errno;
8357
8358 /* Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
8359 if (err == EWOULDBLOCK)
8360 err = EAGAIN;
8361
8362 emacs_gnutls_transport_set_errno (process->gnutls_state, err);
8363
8364 return -1;
8365 }
8366
8367 ssize_t
8368 emacs_gnutls_push (gnutls_transport_ptr_t p, const void* buf, size_t sz)
8369 {
8370 struct Lisp_Process *process = (struct Lisp_Process *)p;
8371 int fd = process->outfd;
8372 ssize_t n = sys_write (fd, buf, sz);
8373
8374 /* 0 or more bytes written means everything went fine. */
8375 if (n >= 0)
8376 return n;
8377
8378 /* Negative bytes written means we got an error in errno.
8379 Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
8380 emacs_gnutls_transport_set_errno (process->gnutls_state,
8381 errno == EWOULDBLOCK ? EAGAIN : errno);
8382
8383 return -1;
8384 }
8385 #endif /* HAVE_GNUTLS */
8386
8387 /* end of w32.c */