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