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