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