Add arch tagline
[bpt/emacs.git] / src / w32.c
CommitLineData
e9e23e23 1/* Utility and Unix shadow routines for GNU Emacs on the Microsoft W32 API.
0b5538bd 2 Copyright (C) 1994, 1995, 2000, 2001, 2002, 2003, 2004,
8cabe764 3 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
95ed0025 4
3b7ad313
EN
5This file is part of GNU Emacs.
6
7GNU Emacs is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
684d6f5b 9the Free Software Foundation; either version 3, or (at your option)
3b7ad313
EN
10any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs; see the file COPYING. If not, write to
4fc5845f
LK
19the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20Boston, MA 02110-1301, USA.
95ed0025
RS
21
22 Geoff Voelker (voelker@cs.washington.edu) 7-29-94
23*/
76b3903d 24#include <stddef.h> /* for offsetof */
95ed0025
RS
25#include <stdlib.h>
26#include <stdio.h>
27#include <io.h>
480b0c5b 28#include <errno.h>
95ed0025
RS
29#include <fcntl.h>
30#include <ctype.h>
480b0c5b 31#include <signal.h>
b3308d2e 32#include <sys/file.h>
480b0c5b 33#include <sys/time.h>
16bb7578 34#include <sys/utime.h>
22189f79 35#include <mbstring.h> /* for _mbspbrk */
480b0c5b
GV
36
37/* must include CRT headers *before* config.h */
4838e624
PJ
38
39#ifdef HAVE_CONFIG_H
40#include <config.h>
41#endif
42
480b0c5b
GV
43#undef access
44#undef chdir
45#undef chmod
46#undef creat
47#undef ctime
48#undef fopen
49#undef link
50#undef mkdir
51#undef mktemp
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
95ed0025 63
d8fcc1b9
AI
64#undef strerror
65
95ed0025 66#include "lisp.h"
95ed0025
RS
67
68#include <pwd.h>
3d19b645 69#include <grp.h>
95ed0025 70
971bce75
AI
71#ifdef __GNUC__
72#define _ANONYMOUS_UNION
73#define _ANONYMOUS_STRUCT
74#endif
480b0c5b 75#include <windows.h>
634d3003 76#include <lmcons.h>
2d5324c5 77#include <shlobj.h>
00b3b7b3 78
480b0c5b
GV
79#ifdef HAVE_SOCKETS /* TCP connection support, if kernel can do it */
80#include <sys/socket.h>
81#undef socket
82#undef bind
83#undef connect
84#undef htons
85#undef ntohs
86#undef inet_addr
87#undef gethostname
88#undef gethostbyname
89#undef getservbyname
ecd270eb 90#undef getpeername
380961a6 91#undef shutdown
962955c5
JR
92#undef setsockopt
93#undef listen
94#undef getsockname
95#undef accept
96#undef recvfrom
97#undef sendto
480b0c5b 98#endif
00b3b7b3 99
489f9371 100#include "w32.h"
480b0c5b 101#include "ndir.h"
489f9371 102#include "w32heap.h"
253574a6
JR
103#include "systime.h"
104
2d5324c5
JR
105typedef HRESULT (WINAPI * ShGetFolderPath_fn)
106 (IN HWND, IN int, IN HANDLE, IN DWORD, OUT char *);
107
9785d95b
BK
108void globals_of_w32 ();
109
76b3903d
GV
110extern Lisp_Object Vw32_downcase_file_names;
111extern Lisp_Object Vw32_generate_fake_inodes;
112extern Lisp_Object Vw32_get_true_file_attributes;
e0c181dd 113extern int w32_num_mouse_buttons;
76b3903d 114
18e070ac 115\f
9785d95b 116/*
aa5ee2a3 117 Initialization states
9785d95b
BK
118 */
119static BOOL g_b_init_is_windows_9x;
120static BOOL g_b_init_open_process_token;
121static BOOL g_b_init_get_token_information;
122static BOOL g_b_init_lookup_account_sid;
123static BOOL g_b_init_get_sid_identifier_authority;
c617afce
EZ
124static BOOL g_b_init_get_sid_sub_authority;
125static BOOL g_b_init_get_sid_sub_authority_count;
9785d95b 126
f60ae425
BK
127/*
128 BEGIN: Wrapper functions around OpenProcessToken
129 and other functions in advapi32.dll that are only
130 supported in Windows NT / 2k / XP
131*/
132 /* ** Function pointer typedefs ** */
133typedef BOOL (WINAPI * OpenProcessToken_Proc) (
134 HANDLE ProcessHandle,
135 DWORD DesiredAccess,
136 PHANDLE TokenHandle);
137typedef BOOL (WINAPI * GetTokenInformation_Proc) (
138 HANDLE TokenHandle,
139 TOKEN_INFORMATION_CLASS TokenInformationClass,
140 LPVOID TokenInformation,
141 DWORD TokenInformationLength,
142 PDWORD ReturnLength);
74258518
JR
143typedef BOOL (WINAPI * GetProcessTimes_Proc) (
144 HANDLE process_handle,
145 LPFILETIME creation_time,
146 LPFILETIME exit_time,
147 LPFILETIME kernel_time,
148 LPFILETIME user_time);
149
150GetProcessTimes_Proc get_process_times_fn = NULL;
151
f60ae425
BK
152#ifdef _UNICODE
153const char * const LookupAccountSid_Name = "LookupAccountSidW";
154#else
155const char * const LookupAccountSid_Name = "LookupAccountSidA";
156#endif
157typedef BOOL (WINAPI * LookupAccountSid_Proc) (
158 LPCTSTR lpSystemName,
159 PSID Sid,
160 LPTSTR Name,
161 LPDWORD cbName,
162 LPTSTR DomainName,
163 LPDWORD cbDomainName,
164 PSID_NAME_USE peUse);
165typedef PSID_IDENTIFIER_AUTHORITY (WINAPI * GetSidIdentifierAuthority_Proc) (
166 PSID pSid);
c617afce
EZ
167typedef PDWORD (WINAPI * GetSidSubAuthority_Proc) (
168 PSID pSid,
169 DWORD n);
170typedef PUCHAR (WINAPI * GetSidSubAuthorityCount_Proc) (
171 PSID pSid);
172
f60ae425
BK
173
174 /* ** A utility function ** */
9bfb11f9
KS
175static BOOL
176is_windows_9x ()
f60ae425 177{
9785d95b 178 static BOOL s_b_ret=0;
f60ae425 179 OSVERSIONINFO os_ver;
9785d95b 180 if (g_b_init_is_windows_9x == 0)
f60ae425 181 {
9785d95b
BK
182 g_b_init_is_windows_9x = 1;
183 ZeroMemory(&os_ver, sizeof(OSVERSIONINFO));
184 os_ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
185 if (GetVersionEx (&os_ver))
186 {
187 s_b_ret = (os_ver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
188 }
f60ae425 189 }
9785d95b 190 return s_b_ret;
f60ae425
BK
191}
192
74258518
JR
193/* Get total user and system times for get-internal-run-time.
194 Returns a list of three integers if the times are provided by the OS
195 (NT derivatives), otherwise it returns the result of current-time. */
196Lisp_Object
197w32_get_internal_run_time ()
198{
199 if (get_process_times_fn)
200 {
201 FILETIME create, exit, kernel, user;
202 HANDLE proc = GetCurrentProcess();
203 if ((*get_process_times_fn) (proc, &create, &exit, &kernel, &user))
204 {
205 LARGE_INTEGER user_int, kernel_int, total;
206 int microseconds;
207 user_int.LowPart = user.dwLowDateTime;
208 user_int.HighPart = user.dwHighDateTime;
209 kernel_int.LowPart = kernel.dwLowDateTime;
210 kernel_int.HighPart = kernel.dwHighDateTime;
211 total.QuadPart = user_int.QuadPart + kernel_int.QuadPart;
212 /* FILETIME is 100 nanosecond increments, Emacs only wants
213 microsecond resolution. */
214 total.QuadPart /= 10;
215 microseconds = total.QuadPart % 1000000;
216 total.QuadPart /= 1000000;
217
218 /* Sanity check to make sure we can represent the result. */
219 if (total.HighPart == 0)
220 {
221 int secs = total.LowPart;
222
223 return list3 (make_number ((secs >> 16) & 0xffff),
224 make_number (secs & 0xffff),
225 make_number (microseconds));
226 }
227 }
228 }
229
230 return Fcurrent_time ();
231}
232
f60ae425
BK
233 /* ** The wrapper functions ** */
234
235BOOL WINAPI open_process_token (
236 HANDLE ProcessHandle,
237 DWORD DesiredAccess,
238 PHANDLE TokenHandle)
239{
9785d95b 240 static OpenProcessToken_Proc s_pfn_Open_Process_Token = NULL;
f60ae425
BK
241 HMODULE hm_advapi32 = NULL;
242 if (is_windows_9x () == TRUE)
243 {
244 return FALSE;
245 }
9785d95b
BK
246 if (g_b_init_open_process_token == 0)
247 {
248 g_b_init_open_process_token = 1;
249 hm_advapi32 = LoadLibrary ("Advapi32.dll");
250 s_pfn_Open_Process_Token =
251 (OpenProcessToken_Proc) GetProcAddress (hm_advapi32, "OpenProcessToken");
252 }
253 if (s_pfn_Open_Process_Token == NULL)
f60ae425
BK
254 {
255 return FALSE;
256 }
257 return (
9785d95b 258 s_pfn_Open_Process_Token (
f60ae425
BK
259 ProcessHandle,
260 DesiredAccess,
261 TokenHandle)
262 );
263}
264
265BOOL WINAPI get_token_information (
266 HANDLE TokenHandle,
267 TOKEN_INFORMATION_CLASS TokenInformationClass,
268 LPVOID TokenInformation,
269 DWORD TokenInformationLength,
270 PDWORD ReturnLength)
271{
9785d95b 272 static GetTokenInformation_Proc s_pfn_Get_Token_Information = NULL;
f60ae425
BK
273 HMODULE hm_advapi32 = NULL;
274 if (is_windows_9x () == TRUE)
275 {
276 return FALSE;
277 }
9785d95b
BK
278 if (g_b_init_get_token_information == 0)
279 {
280 g_b_init_get_token_information = 1;
281 hm_advapi32 = LoadLibrary ("Advapi32.dll");
282 s_pfn_Get_Token_Information =
283 (GetTokenInformation_Proc) GetProcAddress (hm_advapi32, "GetTokenInformation");
284 }
285 if (s_pfn_Get_Token_Information == NULL)
f60ae425
BK
286 {
287 return FALSE;
288 }
289 return (
9785d95b 290 s_pfn_Get_Token_Information (
f60ae425
BK
291 TokenHandle,
292 TokenInformationClass,
293 TokenInformation,
294 TokenInformationLength,
295 ReturnLength)
296 );
297}
298
299BOOL WINAPI lookup_account_sid (
300 LPCTSTR lpSystemName,
301 PSID Sid,
302 LPTSTR Name,
303 LPDWORD cbName,
304 LPTSTR DomainName,
305 LPDWORD cbDomainName,
306 PSID_NAME_USE peUse)
307{
9785d95b 308 static LookupAccountSid_Proc s_pfn_Lookup_Account_Sid = NULL;
f60ae425
BK
309 HMODULE hm_advapi32 = NULL;
310 if (is_windows_9x () == TRUE)
311 {
312 return FALSE;
313 }
9785d95b
BK
314 if (g_b_init_lookup_account_sid == 0)
315 {
316 g_b_init_lookup_account_sid = 1;
317 hm_advapi32 = LoadLibrary ("Advapi32.dll");
318 s_pfn_Lookup_Account_Sid =
319 (LookupAccountSid_Proc) GetProcAddress (hm_advapi32, LookupAccountSid_Name);
320 }
321 if (s_pfn_Lookup_Account_Sid == NULL)
f60ae425
BK
322 {
323 return FALSE;
324 }
325 return (
9785d95b 326 s_pfn_Lookup_Account_Sid (
f60ae425
BK
327 lpSystemName,
328 Sid,
329 Name,
330 cbName,
331 DomainName,
332 cbDomainName,
333 peUse)
334 );
335}
336
337PSID_IDENTIFIER_AUTHORITY WINAPI get_sid_identifier_authority (
338 PSID pSid)
339{
9785d95b 340 static GetSidIdentifierAuthority_Proc s_pfn_Get_Sid_Identifier_Authority = NULL;
f60ae425
BK
341 HMODULE hm_advapi32 = NULL;
342 if (is_windows_9x () == TRUE)
343 {
344 return NULL;
345 }
9785d95b
BK
346 if (g_b_init_get_sid_identifier_authority == 0)
347 {
348 g_b_init_get_sid_identifier_authority = 1;
349 hm_advapi32 = LoadLibrary ("Advapi32.dll");
350 s_pfn_Get_Sid_Identifier_Authority =
351 (GetSidIdentifierAuthority_Proc) GetProcAddress (
352 hm_advapi32, "GetSidIdentifierAuthority");
353 }
354 if (s_pfn_Get_Sid_Identifier_Authority == NULL)
f60ae425
BK
355 {
356 return NULL;
357 }
9785d95b 358 return (s_pfn_Get_Sid_Identifier_Authority (pSid));
f60ae425
BK
359}
360
c617afce
EZ
361PDWORD WINAPI get_sid_sub_authority (
362 PSID pSid,
363 DWORD n)
364{
365 static GetSidSubAuthority_Proc s_pfn_Get_Sid_Sub_Authority = NULL;
6811b9f4 366 static DWORD zero = 0U;
c617afce
EZ
367 HMODULE hm_advapi32 = NULL;
368 if (is_windows_9x () == TRUE)
369 {
6811b9f4 370 return &zero;
c617afce
EZ
371 }
372 if (g_b_init_get_sid_sub_authority == 0)
373 {
374 g_b_init_get_sid_sub_authority = 1;
375 hm_advapi32 = LoadLibrary ("Advapi32.dll");
376 s_pfn_Get_Sid_Sub_Authority =
377 (GetSidSubAuthority_Proc) GetProcAddress (
378 hm_advapi32, "GetSidSubAuthority");
379 }
380 if (s_pfn_Get_Sid_Sub_Authority == NULL)
381 {
6811b9f4 382 return &zero;
c617afce
EZ
383 }
384 return (s_pfn_Get_Sid_Sub_Authority (pSid, n));
385}
386
387PUCHAR WINAPI get_sid_sub_authority_count (
388 PSID pSid)
389{
390 static GetSidSubAuthorityCount_Proc s_pfn_Get_Sid_Sub_Authority_Count = NULL;
6811b9f4 391 static UCHAR zero = 0U;
c617afce
EZ
392 HMODULE hm_advapi32 = NULL;
393 if (is_windows_9x () == TRUE)
394 {
6811b9f4 395 return &zero;
c617afce
EZ
396 }
397 if (g_b_init_get_sid_sub_authority_count == 0)
398 {
399 g_b_init_get_sid_sub_authority_count = 1;
400 hm_advapi32 = LoadLibrary ("Advapi32.dll");
401 s_pfn_Get_Sid_Sub_Authority_Count =
402 (GetSidSubAuthorityCount_Proc) GetProcAddress (
403 hm_advapi32, "GetSidSubAuthorityCount");
404 }
405 if (s_pfn_Get_Sid_Sub_Authority_Count == NULL)
406 {
6811b9f4 407 return &zero;
c617afce
EZ
408 }
409 return (s_pfn_Get_Sid_Sub_Authority_Count (pSid));
410}
411
f60ae425
BK
412/*
413 END: Wrapper functions around OpenProcessToken
414 and other functions in advapi32.dll that are only
415 supported in Windows NT / 2k / XP
416*/
417
418\f
18e070ac
AI
419/* Equivalent of strerror for W32 error codes. */
420char *
421w32_strerror (int error_no)
422{
423 static char buf[500];
424
425 if (error_no == 0)
426 error_no = GetLastError ();
427
428 buf[0] = '\0';
429 if (!FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL,
430 error_no,
431 0, /* choose most suitable language */
432 buf, sizeof (buf), NULL))
433 sprintf (buf, "w32 error %u", error_no);
434 return buf;
435}
436
ed91b2ad
EZ
437/* Return 1 if P is a valid pointer to an object of size SIZE. Return
438 0 if P is NOT a valid pointer. Return -1 if we cannot validate P.
439
440 This is called from alloc.c:valid_pointer_p. */
441int
442w32_valid_pointer_p (void *p, int size)
443{
444 SIZE_T done;
445 HANDLE h = OpenProcess (PROCESS_VM_READ, FALSE, GetCurrentProcessId ());
446
447 if (h)
448 {
449 unsigned char *buf = alloca (size);
450 int retval = ReadProcessMemory (h, p, buf, size, &done);
451
452 CloseHandle (h);
453 return retval;
454 }
455 else
456 return -1;
457}
458
76b3903d 459static char startup_dir[MAXPATHLEN];
00b3b7b3 460
95ed0025 461/* Get the current working directory. */
480b0c5b 462char *
95ed0025
RS
463getwd (char *dir)
464{
76b3903d 465#if 0
480b0c5b
GV
466 if (GetCurrentDirectory (MAXPATHLEN, dir) > 0)
467 return dir;
468 return NULL;
76b3903d
GV
469#else
470 /* Emacs doesn't actually change directory itself, and we want to
471 force our real wd to be where emacs.exe is to avoid unnecessary
472 conflicts when trying to rename or delete directories. */
473 strcpy (dir, startup_dir);
474 return dir;
475#endif
95ed0025
RS
476}
477
480b0c5b 478#ifndef HAVE_SOCKETS
95ed0025
RS
479/* Emulate gethostname. */
480int
481gethostname (char *buffer, int size)
482{
177c0ea7 483 /* NT only allows small host names, so the buffer is
95ed0025
RS
484 certainly large enough. */
485 return !GetComputerName (buffer, &size);
486}
480b0c5b 487#endif /* HAVE_SOCKETS */
95ed0025
RS
488
489/* Emulate getloadavg. */
490int
491getloadavg (double loadavg[], int nelem)
492{
493 int i;
494
495 /* A faithful emulation is going to have to be saved for a rainy day. */
177c0ea7 496 for (i = 0; i < nelem; i++)
95ed0025
RS
497 {
498 loadavg[i] = 0.0;
499 }
500 return i;
501}
502
480b0c5b 503/* Emulate getpwuid, getpwnam and others. */
95ed0025 504
051fe60d
GV
505#define PASSWD_FIELD_SIZE 256
506
507static char the_passwd_name[PASSWD_FIELD_SIZE];
508static char the_passwd_passwd[PASSWD_FIELD_SIZE];
509static char the_passwd_gecos[PASSWD_FIELD_SIZE];
510static char the_passwd_dir[PASSWD_FIELD_SIZE];
511static char the_passwd_shell[PASSWD_FIELD_SIZE];
95ed0025 512
177c0ea7 513static struct passwd the_passwd =
95ed0025
RS
514{
515 the_passwd_name,
516 the_passwd_passwd,
517 0,
518 0,
519 0,
520 the_passwd_gecos,
521 the_passwd_dir,
522 the_passwd_shell,
523};
524
3d19b645
LH
525static struct group the_group =
526{
527 /* There are no groups on NT, so we just return "root" as the
528 group name. */
529 "root",
530};
531
177c0ea7
JB
532int
533getuid ()
534{
480b0c5b
GV
535 return the_passwd.pw_uid;
536}
537
177c0ea7
JB
538int
539geteuid ()
540{
480b0c5b
GV
541 /* I could imagine arguing for checking to see whether the user is
542 in the Administrators group and returning a UID of 0 for that
543 case, but I don't know how wise that would be in the long run. */
177c0ea7 544 return getuid ();
480b0c5b
GV
545}
546
177c0ea7
JB
547int
548getgid ()
549{
480b0c5b
GV
550 return the_passwd.pw_gid;
551}
552
177c0ea7
JB
553int
554getegid ()
555{
480b0c5b
GV
556 return getgid ();
557}
558
95ed0025
RS
559struct passwd *
560getpwuid (int uid)
561{
480b0c5b
GV
562 if (uid == the_passwd.pw_uid)
563 return &the_passwd;
564 return NULL;
95ed0025
RS
565}
566
3d19b645
LH
567struct group *
568getgrgid (gid_t gid)
569{
570 return &the_group;
571}
572
95ed0025
RS
573struct passwd *
574getpwnam (char *name)
575{
576 struct passwd *pw;
177c0ea7 577
95ed0025
RS
578 pw = getpwuid (getuid ());
579 if (!pw)
580 return pw;
581
480b0c5b 582 if (stricmp (name, pw->pw_name))
95ed0025
RS
583 return NULL;
584
585 return pw;
586}
587
480b0c5b
GV
588void
589init_user_info ()
95ed0025 590{
480b0c5b
GV
591 /* Find the user's real name by opening the process token and
592 looking up the name associated with the user-sid in that token.
593
594 Use the relative portion of the identifier authority value from
595 the user-sid as the user id value (same for group id using the
596 primary group sid from the process token). */
597
634d3003 598 char name[UNLEN+1], domain[1025];
10aabbf9
JB
599 DWORD length = sizeof (name), dlength = sizeof (domain), trash;
600 HANDLE token = NULL;
601 SID_NAME_USE user_type;
634d3003
EZ
602 unsigned char buf[1024];
603 TOKEN_USER user_token;
604 TOKEN_PRIMARY_GROUP group_token;
10aabbf9
JB
605
606 if (open_process_token (GetCurrentProcess (), TOKEN_QUERY, &token)
607 && get_token_information (token, TokenUser,
634d3003
EZ
608 (PVOID)buf, sizeof (buf), &trash)
609 && (memcpy (&user_token, buf, sizeof (user_token)),
610 lookup_account_sid (NULL, user_token.User.Sid, name, &length,
611 domain, &dlength, &user_type)))
d1c1c3d2 612 {
480b0c5b 613 strcpy (the_passwd.pw_name, name);
c617afce 614 /* Determine a reasonable uid value. */
480b0c5b
GV
615 if (stricmp ("administrator", name) == 0)
616 {
c617afce
EZ
617 the_passwd.pw_uid = 500; /* well-known Administrator uid */
618 the_passwd.pw_gid = 513; /* well-known None gid */
480b0c5b
GV
619 }
620 else
621 {
ce0ee994
EZ
622 /* Use the last sub-authority value of the RID, the relative
623 portion of the SID, as user/group ID. */
c617afce 624 DWORD n_subauthorities =
634d3003 625 *get_sid_sub_authority_count (user_token.User.Sid);
c617afce
EZ
626
627 if (n_subauthorities < 1)
628 the_passwd.pw_uid = 0; /* the "World" RID */
629 else
630 {
631 the_passwd.pw_uid =
634d3003 632 *get_sid_sub_authority (user_token.User.Sid,
c617afce
EZ
633 n_subauthorities - 1);
634 /* Restrict to conventional uid range for normal users. */
635 the_passwd.pw_uid %= 60001;
636 }
480b0c5b
GV
637
638 /* Get group id */
f60ae425 639 if (get_token_information (token, TokenPrimaryGroup,
634d3003 640 (PVOID)buf, sizeof (buf), &trash))
480b0c5b 641 {
634d3003 642 memcpy (&group_token, buf, sizeof (group_token));
c617afce 643 n_subauthorities =
634d3003 644 *get_sid_sub_authority_count (group_token.PrimaryGroup);
c617afce
EZ
645
646 if (n_subauthorities < 1)
647 the_passwd.pw_gid = 0; /* the "World" RID */
648 else
649 {
650 the_passwd.pw_gid =
634d3003 651 *get_sid_sub_authority (group_token.PrimaryGroup,
c617afce
EZ
652 n_subauthorities - 1);
653 /* I don't know if this is necessary, but for safety... */
654 the_passwd.pw_gid %= 60001;
655 }
480b0c5b
GV
656 }
657 else
658 the_passwd.pw_gid = the_passwd.pw_uid;
659 }
660 }
661 /* If security calls are not supported (presumably because we
10aabbf9 662 are running under Windows 95), fallback to this. */
480b0c5b
GV
663 else if (GetUserName (name, &length))
664 {
665 strcpy (the_passwd.pw_name, name);
666 if (stricmp ("administrator", name) == 0)
667 the_passwd.pw_uid = 0;
668 else
669 the_passwd.pw_uid = 123;
670 the_passwd.pw_gid = the_passwd.pw_uid;
671 }
672 else
673 {
674 strcpy (the_passwd.pw_name, "unknown");
675 the_passwd.pw_uid = 123;
676 the_passwd.pw_gid = 123;
d1c1c3d2 677 }
95ed0025 678
480b0c5b
GV
679 /* Ensure HOME and SHELL are defined. */
680 if (getenv ("HOME") == NULL)
ca149beb 681 abort ();
480b0c5b 682 if (getenv ("SHELL") == NULL)
ca149beb 683 abort ();
95ed0025 684
480b0c5b
GV
685 /* Set dir and shell from environment variables. */
686 strcpy (the_passwd.pw_dir, getenv ("HOME"));
687 strcpy (the_passwd.pw_shell, getenv ("SHELL"));
bd4a449f 688
480b0c5b
GV
689 if (token)
690 CloseHandle (token);
95ed0025
RS
691}
692
95ed0025 693int
480b0c5b 694random ()
95ed0025 695{
480b0c5b
GV
696 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
697 return ((rand () << 15) | rand ());
95ed0025
RS
698}
699
95ed0025 700void
480b0c5b 701srandom (int seed)
95ed0025 702{
480b0c5b 703 srand (seed);
95ed0025
RS
704}
705
76b3903d 706
cbe39279
RS
707/* Normalize filename by converting all path separators to
708 the specified separator. Also conditionally convert upper
709 case path name components to lower case. */
710
711static void
712normalize_filename (fp, path_sep)
713 register char *fp;
714 char path_sep;
715{
716 char sep;
717 char *elem;
718
5162ffce
MB
719 /* Always lower-case drive letters a-z, even if the filesystem
720 preserves case in filenames.
721 This is so filenames can be compared by string comparison
722 functions that are case-sensitive. Even case-preserving filesystems
723 do not distinguish case in drive letters. */
724 if (fp[1] == ':' && *fp >= 'A' && *fp <= 'Z')
725 {
726 *fp += 'a' - 'A';
727 fp += 2;
728 }
729
fbd6baed 730 if (NILP (Vw32_downcase_file_names))
cbe39279
RS
731 {
732 while (*fp)
733 {
734 if (*fp == '/' || *fp == '\\')
735 *fp = path_sep;
736 fp++;
737 }
738 return;
739 }
740
741 sep = path_sep; /* convert to this path separator */
742 elem = fp; /* start of current path element */
743
744 do {
745 if (*fp >= 'a' && *fp <= 'z')
746 elem = 0; /* don't convert this element */
747
748 if (*fp == 0 || *fp == ':')
749 {
750 sep = *fp; /* restore current separator (or 0) */
751 *fp = '/'; /* after conversion of this element */
752 }
753
754 if (*fp == '/' || *fp == '\\')
755 {
756 if (elem && elem != fp)
757 {
758 *fp = 0; /* temporary end of string */
759 _strlwr (elem); /* while we convert to lower case */
760 }
761 *fp = sep; /* convert (or restore) path separator */
762 elem = fp + 1; /* next element starts after separator */
763 sep = path_sep;
764 }
765 } while (*fp++);
766}
767
480b0c5b 768/* Destructively turn backslashes into slashes. */
95ed0025 769void
480b0c5b
GV
770dostounix_filename (p)
771 register char *p;
95ed0025 772{
cbe39279 773 normalize_filename (p, '/');
95ed0025
RS
774}
775
480b0c5b 776/* Destructively turn slashes into backslashes. */
95ed0025 777void
480b0c5b
GV
778unixtodos_filename (p)
779 register char *p;
95ed0025 780{
cbe39279 781 normalize_filename (p, '\\');
95ed0025
RS
782}
783
480b0c5b
GV
784/* Remove all CR's that are followed by a LF.
785 (From msdos.c...probably should figure out a way to share it,
786 although this code isn't going to ever change.) */
35f0d482 787int
480b0c5b
GV
788crlf_to_lf (n, buf)
789 register int n;
790 register unsigned char *buf;
35f0d482 791{
480b0c5b
GV
792 unsigned char *np = buf;
793 unsigned char *startp = buf;
794 unsigned char *endp = buf + n;
35f0d482 795
480b0c5b
GV
796 if (n == 0)
797 return n;
798 while (buf < endp - 1)
95ed0025 799 {
480b0c5b
GV
800 if (*buf == 0x0d)
801 {
802 if (*(++buf) != 0x0a)
803 *np++ = 0x0d;
804 }
805 else
806 *np++ = *buf++;
95ed0025 807 }
480b0c5b
GV
808 if (buf < endp)
809 *np++ = *buf++;
810 return np - startp;
95ed0025
RS
811}
812
76b3903d
GV
813/* Parse the root part of file name, if present. Return length and
814 optionally store pointer to char after root. */
815static int
816parse_root (char * name, char ** pPath)
817{
818 char * start = name;
819
820 if (name == NULL)
821 return 0;
822
823 /* find the root name of the volume if given */
824 if (isalpha (name[0]) && name[1] == ':')
825 {
826 /* skip past drive specifier */
827 name += 2;
828 if (IS_DIRECTORY_SEP (name[0]))
829 name++;
830 }
831 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
832 {
833 int slashes = 2;
834 name += 2;
835 do
836 {
837 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
838 break;
839 name++;
840 }
841 while ( *name );
842 if (IS_DIRECTORY_SEP (name[0]))
843 name++;
844 }
845
846 if (pPath)
847 *pPath = name;
848
849 return name - start;
850}
851
852/* Get long base name for name; name is assumed to be absolute. */
853static int
854get_long_basename (char * name, char * buf, int size)
855{
856 WIN32_FIND_DATA find_data;
857 HANDLE dir_handle;
858 int len = 0;
859
9ab8560d 860 /* must be valid filename, no wild cards or other invalid characters */
22189f79 861 if (_mbspbrk (name, "*?|<>\""))
bb1584c8
RS
862 return 0;
863
76b3903d
GV
864 dir_handle = FindFirstFile (name, &find_data);
865 if (dir_handle != INVALID_HANDLE_VALUE)
866 {
867 if ((len = strlen (find_data.cFileName)) < size)
868 memcpy (buf, find_data.cFileName, len + 1);
869 else
870 len = 0;
871 FindClose (dir_handle);
872 }
873 return len;
874}
875
876/* Get long name for file, if possible (assumed to be absolute). */
877BOOL
878w32_get_long_filename (char * name, char * buf, int size)
879{
880 char * o = buf;
881 char * p;
882 char * q;
883 char full[ MAX_PATH ];
884 int len;
885
886 len = strlen (name);
887 if (len >= MAX_PATH)
888 return FALSE;
889
890 /* Use local copy for destructive modification. */
891 memcpy (full, name, len+1);
892 unixtodos_filename (full);
893
894 /* Copy root part verbatim. */
895 len = parse_root (full, &p);
896 memcpy (o, full, len);
897 o += len;
4f8ac0b2 898 *o = '\0';
76b3903d
GV
899 size -= len;
900
4f8ac0b2 901 while (p != NULL && *p)
76b3903d
GV
902 {
903 q = p;
904 p = strchr (q, '\\');
905 if (p) *p = '\0';
906 len = get_long_basename (full, o, size);
907 if (len > 0)
908 {
909 o += len;
910 size -= len;
911 if (p != NULL)
912 {
913 *p++ = '\\';
914 if (size < 2)
915 return FALSE;
916 *o++ = '\\';
917 size--;
918 *o = '\0';
919 }
920 }
921 else
922 return FALSE;
923 }
76b3903d
GV
924
925 return TRUE;
926}
927
9d3355d1
GV
928int
929is_unc_volume (const char *filename)
930{
931 const char *ptr = filename;
932
933 if (!IS_DIRECTORY_SEP (ptr[0]) || !IS_DIRECTORY_SEP (ptr[1]) || !ptr[2])
934 return 0;
935
22189f79 936 if (_mbspbrk (ptr + 2, "*?|<>\"\\/"))
9d3355d1
GV
937 return 0;
938
939 return 1;
940}
76b3903d 941
95ed0025
RS
942/* Routines that are no-ops on NT but are defined to get Emacs to compile. */
943
177c0ea7
JB
944int
945sigsetmask (int signal_mask)
946{
95ed0025
RS
947 return 0;
948}
949
177c0ea7
JB
950int
951sigmask (int sig)
952{
8f900f6e
AI
953 return 0;
954}
955
177c0ea7
JB
956int
957sigblock (int sig)
958{
95ed0025
RS
959 return 0;
960}
961
177c0ea7
JB
962int
963sigunblock (int sig)
964{
8f900f6e
AI
965 return 0;
966}
967
177c0ea7
JB
968int
969setpgrp (int pid, int gid)
970{
95ed0025
RS
971 return 0;
972}
973
177c0ea7
JB
974int
975alarm (int seconds)
976{
95ed0025
RS
977 return 0;
978}
979
480b0c5b 980#define REG_ROOT "SOFTWARE\\GNU\\Emacs"
f332b293 981
177c0ea7 982LPBYTE
fbd6baed 983w32_get_resource (key, lpdwtype)
f332b293
GV
984 char *key;
985 LPDWORD lpdwtype;
986{
987 LPBYTE lpvalue;
988 HKEY hrootkey = NULL;
989 DWORD cbData;
177c0ea7
JB
990
991 /* Check both the current user and the local machine to see if
f332b293 992 we have any resources. */
177c0ea7 993
f332b293
GV
994 if (RegOpenKeyEx (HKEY_CURRENT_USER, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
995 {
996 lpvalue = NULL;
997
177c0ea7
JB
998 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
999 && (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL
f332b293
GV
1000 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
1001 {
4da4d9bb 1002 RegCloseKey (hrootkey);
f332b293
GV
1003 return (lpvalue);
1004 }
1005
1006 if (lpvalue) xfree (lpvalue);
177c0ea7 1007
f332b293 1008 RegCloseKey (hrootkey);
177c0ea7
JB
1009 }
1010
f332b293
GV
1011 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
1012 {
1013 lpvalue = NULL;
177c0ea7 1014
76b3903d
GV
1015 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
1016 && (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL
1017 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
f332b293 1018 {
4da4d9bb 1019 RegCloseKey (hrootkey);
f332b293
GV
1020 return (lpvalue);
1021 }
177c0ea7 1022
f332b293 1023 if (lpvalue) xfree (lpvalue);
177c0ea7 1024
f332b293 1025 RegCloseKey (hrootkey);
177c0ea7
JB
1026 }
1027
f332b293
GV
1028 return (NULL);
1029}
1030
75b08edb
GV
1031char *get_emacs_configuration (void);
1032extern Lisp_Object Vsystem_configuration;
1033
f332b293 1034void
aa7b87b0 1035init_environment (char ** argv)
f332b293 1036{
b3308d2e
KH
1037 static const char * const tempdirs[] = {
1038 "$TMPDIR", "$TEMP", "$TMP", "c:/"
1039 };
2d5324c5 1040
b3308d2e 1041 int i;
2d5324c5 1042
b3308d2e
KH
1043 const int imax = sizeof (tempdirs) / sizeof (tempdirs[0]);
1044
1045 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
1046 temporary files and assume "/tmp" if $TMPDIR is unset, which
1047 will break on DOS/Windows. Refuse to work if we cannot find
1048 a directory, not even "c:/", usable for that purpose. */
1049 for (i = 0; i < imax ; i++)
1050 {
1051 const char *tmp = tempdirs[i];
1052
1053 if (*tmp == '$')
1054 tmp = getenv (tmp + 1);
1055 /* Note that `access' can lie to us if the directory resides on a
1056 read-only filesystem, like CD-ROM or a write-protected floppy.
1057 The only way to be really sure is to actually create a file and
1058 see if it succeeds. But I think that's too much to ask. */
a302c7ae 1059 if (tmp && _access (tmp, D_OK) == 0)
b3308d2e
KH
1060 {
1061 char * var = alloca (strlen (tmp) + 8);
1062 sprintf (var, "TMPDIR=%s", tmp);
aca583b2 1063 _putenv (strdup (var));
b3308d2e
KH
1064 break;
1065 }
1066 }
1067 if (i >= imax)
1068 cmd_error_internal
1069 (Fcons (Qerror,
1070 Fcons (build_string ("no usable temporary directories found!!"),
1071 Qnil)),
1072 "While setting TMPDIR: ");
1073
ca149beb
AI
1074 /* Check for environment variables and use registry settings if they
1075 don't exist. Fallback on default values where applicable. */
f332b293 1076 {
480b0c5b
GV
1077 int i;
1078 LPBYTE lpval;
1079 DWORD dwType;
69fb0241 1080 char locale_name[32];
2d5324c5
JR
1081 struct stat ignored;
1082 char default_home[MAX_PATH];
f332b293 1083
e00b99c8 1084 static const struct env_entry
ca149beb
AI
1085 {
1086 char * name;
1087 char * def_value;
e00b99c8 1088 } dflt_envvars[] =
ca149beb
AI
1089 {
1090 {"HOME", "C:/"},
1091 {"PRELOAD_WINSOCK", NULL},
1092 {"emacs_dir", "C:/emacs"},
cc14250a 1093 {"EMACSLOADPATH", "%emacs_dir%/site-lisp;%emacs_dir%/../site-lisp;%emacs_dir%/lisp;%emacs_dir%/leim"},
ca149beb
AI
1094 {"SHELL", "%emacs_dir%/bin/cmdproxy.exe"},
1095 {"EMACSDATA", "%emacs_dir%/etc"},
1096 {"EMACSPATH", "%emacs_dir%/bin"},
76b3903d 1097 /* We no longer set INFOPATH because Info-default-directory-list
ca149beb
AI
1098 is then ignored. */
1099 /* {"INFOPATH", "%emacs_dir%/info"}, */
1100 {"EMACSDOC", "%emacs_dir%/etc"},
69fb0241
JR
1101 {"TERM", "cmd"},
1102 {"LANG", NULL},
480b0c5b
GV
1103 };
1104
e00b99c8
EZ
1105#define N_ENV_VARS sizeof(dflt_envvars)/sizeof(dflt_envvars[0])
1106
1107 /* We need to copy dflt_envvars[] and work on the copy because we
1108 don't want the dumped Emacs to inherit the values of
1109 environment variables we saw during dumping (which could be on
1110 a different system). The defaults above must be left intact. */
1111 struct env_entry env_vars[N_ENV_VARS];
1112
1113 for (i = 0; i < N_ENV_VARS; i++)
1114 env_vars[i] = dflt_envvars[i];
1115
2d5324c5
JR
1116 /* For backwards compatibility, check if a .emacs file exists in C:/
1117 If not, then we can try to default to the appdata directory under the
1118 user's profile, which is more likely to be writable. */
1119 if (stat ("C:/.emacs", &ignored) < 0)
1120 {
1121 HRESULT profile_result;
1122 /* Dynamically load ShGetFolderPath, as it won't exist on versions
1123 of Windows 95 and NT4 that have not been updated to include
1124 MSIE 5. Also we don't link with shell32.dll by default. */
1125 HMODULE shell32_dll;
1126 ShGetFolderPath_fn get_folder_path;
1127 shell32_dll = GetModuleHandle ("shell32.dll");
1128 get_folder_path = (ShGetFolderPath_fn)
1129 GetProcAddress (shell32_dll, "SHGetFolderPathA");
1130
1131 if (get_folder_path != NULL)
1132 {
1133 profile_result = get_folder_path (NULL, CSIDL_APPDATA, NULL,
1134 0, default_home);
1135
1136 /* If we can't get the appdata dir, revert to old behaviour. */
1137 if (profile_result == S_OK)
1138 env_vars[0].def_value = default_home;
1139 }
1140
1141 /* Unload shell32.dll, it is not needed anymore. */
1142 FreeLibrary (shell32_dll);
1143 }
1144
69fb0241
JR
1145 /* Get default locale info and use it for LANG. */
1146 if (GetLocaleInfo (LOCALE_USER_DEFAULT,
1147 LOCALE_SABBREVLANGNAME | LOCALE_USE_CP_ACP,
1148 locale_name, sizeof (locale_name)))
1149 {
e00b99c8 1150 for (i = 0; i < N_ENV_VARS; i++)
69fb0241
JR
1151 {
1152 if (strcmp (env_vars[i].name, "LANG") == 0)
1153 {
1154 env_vars[i].def_value = locale_name;
1155 break;
1156 }
1157 }
1158 }
1159
ca149beb
AI
1160#define SET_ENV_BUF_SIZE (4 * MAX_PATH) /* to cover EMACSLOADPATH */
1161
1162 /* Treat emacs_dir specially: set it unconditionally based on our
1163 location, if it appears that we are running from the bin subdir
1164 of a standard installation. */
1165 {
1166 char *p;
1167 char modname[MAX_PATH];
1168
1169 if (!GetModuleFileName (NULL, modname, MAX_PATH))
1170 abort ();
1171 if ((p = strrchr (modname, '\\')) == NULL)
1172 abort ();
1173 *p = 0;
1174
1175 if ((p = strrchr (modname, '\\')) && stricmp (p, "\\bin") == 0)
1176 {
1177 char buf[SET_ENV_BUF_SIZE];
1178
1179 *p = 0;
1180 for (p = modname; *p; p++)
1181 if (*p == '\\') *p = '/';
177c0ea7 1182
ca149beb 1183 _snprintf (buf, sizeof(buf)-1, "emacs_dir=%s", modname);
a302c7ae 1184 _putenv (strdup (buf));
ca149beb 1185 }
950090be
JR
1186 /* Handle running emacs from the build directory: src/oo-spd/i386/ */
1187
1188 /* FIXME: should use substring of get_emacs_configuration ().
1189 But I don't think the Windows build supports alpha, mips etc
1190 anymore, so have taken the easy option for now. */
1191 else if (p && stricmp (p, "\\i386") == 0)
1192 {
1193 *p = 0;
1194 p = strrchr (modname, '\\');
1195 if (p != NULL)
1196 {
1197 *p = 0;
1198 p = strrchr (modname, '\\');
1199 if (p && stricmp (p, "\\src") == 0)
1200 {
1201 char buf[SET_ENV_BUF_SIZE];
1202
1203 *p = 0;
1204 for (p = modname; *p; p++)
1205 if (*p == '\\') *p = '/';
1206
1207 _snprintf (buf, sizeof(buf)-1, "emacs_dir=%s", modname);
1208 _putenv (strdup (buf));
1209 }
1210 }
1211 }
ca149beb
AI
1212 }
1213
e00b99c8 1214 for (i = 0; i < N_ENV_VARS; i++)
f332b293 1215 {
ca149beb 1216 if (!getenv (env_vars[i].name))
480b0c5b 1217 {
ca149beb 1218 int dont_free = 0;
480b0c5b 1219
aa5ee2a3
JB
1220 if ((lpval = w32_get_resource (env_vars[i].name, &dwType)) == NULL
1221 /* Also ignore empty environment variables. */
1222 || *lpval == 0)
ca149beb 1223 {
14c71d8b 1224 if (lpval) xfree (lpval);
ca149beb
AI
1225 lpval = env_vars[i].def_value;
1226 dwType = REG_EXPAND_SZ;
1227 dont_free = 1;
480b0c5b 1228 }
ca149beb
AI
1229
1230 if (lpval)
480b0c5b 1231 {
892eb237 1232 char buf1[SET_ENV_BUF_SIZE], buf2[SET_ENV_BUF_SIZE];
ca149beb 1233
892eb237
EZ
1234 if (dwType == REG_EXPAND_SZ)
1235 ExpandEnvironmentStrings ((LPSTR) lpval, buf1, sizeof(buf1));
ca149beb 1236 else if (dwType == REG_SZ)
892eb237
EZ
1237 strcpy (buf1, lpval);
1238 if (dwType == REG_EXPAND_SZ || dwType == REG_SZ)
ca149beb 1239 {
892eb237
EZ
1240 _snprintf (buf2, sizeof(buf2)-1, "%s=%s", env_vars[i].name,
1241 buf1);
1242 _putenv (strdup (buf2));
ca149beb 1243 }
f332b293 1244
ca149beb
AI
1245 if (!dont_free)
1246 xfree (lpval);
1247 }
480b0c5b
GV
1248 }
1249 }
1250 }
1251
75b08edb
GV
1252 /* Rebuild system configuration to reflect invoking system. */
1253 Vsystem_configuration = build_string (EMACS_CONFIGURATION);
1254
76b3903d
GV
1255 /* Another special case: on NT, the PATH variable is actually named
1256 "Path" although cmd.exe (perhaps NT itself) arranges for
1257 environment variable lookup and setting to be case insensitive.
1258 However, Emacs assumes a fully case sensitive environment, so we
1259 need to change "Path" to "PATH" to match the expectations of
1260 various elisp packages. We do this by the sneaky method of
1261 modifying the string in the C runtime environ entry.
1262
1263 The same applies to COMSPEC. */
1264 {
1265 char ** envp;
1266
1267 for (envp = environ; *envp; envp++)
1268 if (_strnicmp (*envp, "PATH=", 5) == 0)
1269 memcpy (*envp, "PATH=", 5);
1270 else if (_strnicmp (*envp, "COMSPEC=", 8) == 0)
1271 memcpy (*envp, "COMSPEC=", 8);
1272 }
1273
1274 /* Remember the initial working directory for getwd, then make the
1275 real wd be the location of emacs.exe to avoid conflicts when
1276 renaming or deleting directories. (We also don't call chdir when
1277 running subprocesses for the same reason.) */
1278 if (!GetCurrentDirectory (MAXPATHLEN, startup_dir))
1279 abort ();
1280
1281 {
1282 char *p;
aa7b87b0 1283 static char modname[MAX_PATH];
76b3903d
GV
1284
1285 if (!GetModuleFileName (NULL, modname, MAX_PATH))
1286 abort ();
1287 if ((p = strrchr (modname, '\\')) == NULL)
1288 abort ();
1289 *p = 0;
1290
1291 SetCurrentDirectory (modname);
aa7b87b0
AI
1292
1293 /* Ensure argv[0] has the full path to Emacs. */
1294 *p = '\\';
1295 argv[0] = modname;
76b3903d
GV
1296 }
1297
20af4831
JR
1298 /* Determine if there is a middle mouse button, to allow parse_button
1299 to decide whether right mouse events should be mouse-2 or
1300 mouse-3. */
e0c181dd 1301 w32_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);
20af4831 1302
480b0c5b
GV
1303 init_user_info ();
1304}
1305
bf794306
EZ
1306char *
1307emacs_root_dir (void)
1308{
1309 static char root_dir[FILENAME_MAX];
1310 const char *p;
1311
1312 p = getenv ("emacs_dir");
1313 if (p == NULL)
1314 abort ();
1315 strcpy (root_dir, p);
1316 root_dir[parse_root (root_dir, NULL)] = '\0';
1317 dostounix_filename (root_dir);
1318 return root_dir;
1319}
1320
480b0c5b
GV
1321/* We don't have scripts to automatically determine the system configuration
1322 for Emacs before it's compiled, and we don't want to have to make the
1323 user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
1324 routine. */
1325
480b0c5b
GV
1326char *
1327get_emacs_configuration (void)
1328{
1329 char *arch, *oem, *os;
c5247da2 1330 int build_num;
a302c7ae 1331 static char configuration_buffer[32];
480b0c5b
GV
1332
1333 /* Determine the processor type. */
177c0ea7 1334 switch (get_processor_type ())
480b0c5b
GV
1335 {
1336
1337#ifdef PROCESSOR_INTEL_386
1338 case PROCESSOR_INTEL_386:
1339 case PROCESSOR_INTEL_486:
1340 case PROCESSOR_INTEL_PENTIUM:
1341 arch = "i386";
1342 break;
1343#endif
1344
480b0c5b
GV
1345#ifdef PROCESSOR_MIPS_R2000
1346 case PROCESSOR_MIPS_R2000:
1347 case PROCESSOR_MIPS_R3000:
1348 case PROCESSOR_MIPS_R4000:
1349 arch = "mips";
1350 break;
1351#endif
1352
1353#ifdef PROCESSOR_ALPHA_21064
1354 case PROCESSOR_ALPHA_21064:
1355 arch = "alpha";
1356 break;
1357#endif
1358
1359 default:
1360 arch = "unknown";
1361 break;
f332b293 1362 }
480b0c5b 1363
a302c7ae
AI
1364 /* Use the OEM field to reflect the compiler/library combination. */
1365#ifdef _MSC_VER
1366#define COMPILER_NAME "msvc"
1367#else
1368#ifdef __GNUC__
1369#define COMPILER_NAME "mingw"
1370#else
1371#define COMPILER_NAME "unknown"
1372#endif
1373#endif
1374 oem = COMPILER_NAME;
480b0c5b 1375
c5247da2
GV
1376 switch (osinfo_cache.dwPlatformId) {
1377 case VER_PLATFORM_WIN32_NT:
1378 os = "nt";
1379 build_num = osinfo_cache.dwBuildNumber;
1380 break;
1381 case VER_PLATFORM_WIN32_WINDOWS:
1382 if (osinfo_cache.dwMinorVersion == 0) {
1383 os = "windows95";
1384 } else {
1385 os = "windows98";
1386 }
1387 build_num = LOWORD (osinfo_cache.dwBuildNumber);
1388 break;
1389 case VER_PLATFORM_WIN32s:
1390 /* Not supported, should not happen. */
1391 os = "windows32s";
1392 build_num = LOWORD (osinfo_cache.dwBuildNumber);
1393 break;
1394 default:
1395 os = "unknown";
1396 build_num = 0;
1397 break;
1398 }
1399
1400 if (osinfo_cache.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1401 sprintf (configuration_buffer, "%s-%s-%s%d.%d.%d", arch, oem, os,
1402 get_w32_major_version (), get_w32_minor_version (), build_num);
1403 } else {
1404 sprintf (configuration_buffer, "%s-%s-%s.%d", arch, oem, os, build_num);
1405 }
480b0c5b 1406
480b0c5b 1407 return configuration_buffer;
f332b293
GV
1408}
1409
a302c7ae
AI
1410char *
1411get_emacs_configuration_options (void)
1412{
1413 static char options_buffer[256];
1414
1415/* Work out the effective configure options for this build. */
1416#ifdef _MSC_VER
1417#define COMPILER_VERSION "--with-msvc (%d.%02d)", _MSC_VER / 100, _MSC_VER % 100
1418#else
1419#ifdef __GNUC__
1420#define COMPILER_VERSION "--with-gcc (%d.%d)", __GNUC__, __GNUC_MINOR__
1421#else
1422#define COMPILER_VERSION ""
1423#endif
1424#endif
1425
1426 sprintf (options_buffer, COMPILER_VERSION);
1427#ifdef EMACSDEBUG
1428 strcat (options_buffer, " --no-opt");
1429#endif
1430#ifdef USER_CFLAGS
1431 strcat (options_buffer, " --cflags");
1432 strcat (options_buffer, USER_CFLAGS);
1433#endif
1434#ifdef USER_LDFLAGS
1435 strcat (options_buffer, " --ldflags");
1436 strcat (options_buffer, USER_LDFLAGS);
1437#endif
1438 return options_buffer;
1439}
1440
1441
35f0d482
KH
1442#include <sys/timeb.h>
1443
1444/* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
177c0ea7 1445void
35f0d482
KH
1446gettimeofday (struct timeval *tv, struct timezone *tz)
1447{
6e602566 1448 struct _timeb tb;
35f0d482
KH
1449 _ftime (&tb);
1450
1451 tv->tv_sec = tb.time;
1452 tv->tv_usec = tb.millitm * 1000L;
177c0ea7 1453 if (tz)
35f0d482
KH
1454 {
1455 tz->tz_minuteswest = tb.timezone; /* minutes west of Greenwich */
1456 tz->tz_dsttime = tb.dstflag; /* type of dst correction */
1457 }
1458}
35f0d482 1459
480b0c5b 1460/* ------------------------------------------------------------------------- */
fbd6baed 1461/* IO support and wrapper functions for W32 API. */
480b0c5b 1462/* ------------------------------------------------------------------------- */
95ed0025 1463
480b0c5b 1464/* Place a wrapper around the MSVC version of ctime. It returns NULL
177c0ea7 1465 on network directories, so we handle that case here.
480b0c5b
GV
1466 (Ulrich Leodolter, 1/11/95). */
1467char *
1468sys_ctime (const time_t *t)
1469{
1470 char *str = (char *) ctime (t);
1471 return (str ? str : "Sun Jan 01 00:00:00 1970");
1472}
1473
1474/* Emulate sleep...we could have done this with a define, but that
1475 would necessitate including windows.h in the files that used it.
1476 This is much easier. */
1477void
1478sys_sleep (int seconds)
1479{
1480 Sleep (seconds * 1000);
1481}
1482
76b3903d 1483/* Internal MSVC functions for low-level descriptor munging */
480b0c5b
GV
1484extern int __cdecl _set_osfhnd (int fd, long h);
1485extern int __cdecl _free_osfhnd (int fd);
1486
1487/* parallel array of private info on file handles */
1488filedesc fd_info [ MAXDESC ];
1489
76b3903d
GV
1490typedef struct volume_info_data {
1491 struct volume_info_data * next;
1492
1493 /* time when info was obtained */
1494 DWORD timestamp;
1495
1496 /* actual volume info */
1497 char * root_dir;
480b0c5b
GV
1498 DWORD serialnum;
1499 DWORD maxcomp;
1500 DWORD flags;
76b3903d
GV
1501 char * name;
1502 char * type;
1503} volume_info_data;
1504
1505/* Global referenced by various functions. */
1506static volume_info_data volume_info;
1507
1508/* Vector to indicate which drives are local and fixed (for which cached
1509 data never expires). */
1510static BOOL fixed_drives[26];
1511
1512/* Consider cached volume information to be stale if older than 10s,
1513 at least for non-local drives. Info for fixed drives is never stale. */
1514#define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
1515#define VOLINFO_STILL_VALID( root_dir, info ) \
1516 ( ( isalpha (root_dir[0]) && \
1517 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
1518 || GetTickCount () - info->timestamp < 10000 )
1519
1520/* Cache support functions. */
1521
1522/* Simple linked list with linear search is sufficient. */
1523static volume_info_data *volume_cache = NULL;
1524
1525static volume_info_data *
1526lookup_volume_info (char * root_dir)
1527{
1528 volume_info_data * info;
1529
1530 for (info = volume_cache; info; info = info->next)
1531 if (stricmp (info->root_dir, root_dir) == 0)
1532 break;
1533 return info;
1534}
1535
1536static void
1537add_volume_info (char * root_dir, volume_info_data * info)
1538{
a302c7ae 1539 info->root_dir = xstrdup (root_dir);
76b3903d
GV
1540 info->next = volume_cache;
1541 volume_cache = info;
1542}
1543
1544
1545/* Wrapper for GetVolumeInformation, which uses caching to avoid
1546 performance penalty (~2ms on 486 for local drives, 7.5ms for local
1547 cdrom drive, ~5-10ms or more for remote drives on LAN). */
1548volume_info_data *
1549GetCachedVolumeInformation (char * root_dir)
1550{
1551 volume_info_data * info;
1552 char default_root[ MAX_PATH ];
1553
1554 /* NULL for root_dir means use root from current directory. */
1555 if (root_dir == NULL)
1556 {
1557 if (GetCurrentDirectory (MAX_PATH, default_root) == 0)
1558 return NULL;
1559 parse_root (default_root, &root_dir);
1560 *root_dir = 0;
1561 root_dir = default_root;
1562 }
1563
1564 /* Local fixed drives can be cached permanently. Removable drives
1565 cannot be cached permanently, since the volume name and serial
1566 number (if nothing else) can change. Remote drives should be
1567 treated as if they are removable, since there is no sure way to
1568 tell whether they are or not. Also, the UNC association of drive
1569 letters mapped to remote volumes can be changed at any time (even
1570 by other processes) without notice.
177c0ea7 1571
76b3903d
GV
1572 As a compromise, so we can benefit from caching info for remote
1573 volumes, we use a simple expiry mechanism to invalidate cache
1574 entries that are more than ten seconds old. */
1575
1576#if 0
1577 /* No point doing this, because WNetGetConnection is even slower than
1578 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
1579 GetDriveType is about the only call of this type which does not
1580 involve network access, and so is extremely quick). */
1581
1582 /* Map drive letter to UNC if remote. */
1583 if ( isalpha( root_dir[0] ) && !fixed[ DRIVE_INDEX( root_dir[0] ) ] )
1584 {
1585 char remote_name[ 256 ];
1586 char drive[3] = { root_dir[0], ':' };
1587
1588 if (WNetGetConnection (drive, remote_name, sizeof (remote_name))
1589 == NO_ERROR)
1590 /* do something */ ;
1591 }
1592#endif
1593
1594 info = lookup_volume_info (root_dir);
1595
1596 if (info == NULL || ! VOLINFO_STILL_VALID (root_dir, info))
1597 {
1598 char name[ 256 ];
1599 DWORD serialnum;
1600 DWORD maxcomp;
1601 DWORD flags;
1602 char type[ 256 ];
1603
1604 /* Info is not cached, or is stale. */
1605 if (!GetVolumeInformation (root_dir,
1606 name, sizeof (name),
1607 &serialnum,
1608 &maxcomp,
1609 &flags,
1610 type, sizeof (type)))
1611 return NULL;
1612
1613 /* Cache the volume information for future use, overwriting existing
1614 entry if present. */
1615 if (info == NULL)
1616 {
1617 info = (volume_info_data *) xmalloc (sizeof (volume_info_data));
1618 add_volume_info (root_dir, info);
1619 }
1620 else
1621 {
a302c7ae
AI
1622 xfree (info->name);
1623 xfree (info->type);
76b3903d
GV
1624 }
1625
a302c7ae 1626 info->name = xstrdup (name);
76b3903d
GV
1627 info->serialnum = serialnum;
1628 info->maxcomp = maxcomp;
1629 info->flags = flags;
a302c7ae 1630 info->type = xstrdup (type);
76b3903d
GV
1631 info->timestamp = GetTickCount ();
1632 }
1633
1634 return info;
1635}
480b0c5b
GV
1636
1637/* Get information on the volume where name is held; set path pointer to
1638 start of pathname in name (past UNC header\volume header if present). */
1639int
1640get_volume_info (const char * name, const char ** pPath)
95ed0025 1641{
480b0c5b
GV
1642 char temp[MAX_PATH];
1643 char *rootname = NULL; /* default to current volume */
76b3903d 1644 volume_info_data * info;
480b0c5b
GV
1645
1646 if (name == NULL)
1647 return FALSE;
1648
1649 /* find the root name of the volume if given */
1650 if (isalpha (name[0]) && name[1] == ':')
1651 {
1652 rootname = temp;
1653 temp[0] = *name++;
1654 temp[1] = *name++;
1655 temp[2] = '\\';
1656 temp[3] = 0;
1657 }
1658 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
95ed0025 1659 {
480b0c5b
GV
1660 char *str = temp;
1661 int slashes = 4;
1662 rootname = temp;
1663 do
1664 {
1665 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
1666 break;
1667 *str++ = *name++;
1668 }
1669 while ( *name );
1670
480b0c5b
GV
1671 *str++ = '\\';
1672 *str = 0;
95ed0025 1673 }
480b0c5b
GV
1674
1675 if (pPath)
1676 *pPath = name;
177c0ea7 1677
76b3903d
GV
1678 info = GetCachedVolumeInformation (rootname);
1679 if (info != NULL)
95ed0025 1680 {
76b3903d
GV
1681 /* Set global referenced by other functions. */
1682 volume_info = *info;
480b0c5b 1683 return TRUE;
95ed0025 1684 }
480b0c5b
GV
1685 return FALSE;
1686}
1687
1688/* Determine if volume is FAT format (ie. only supports short 8.3
1689 names); also set path pointer to start of pathname in name. */
1690int
1691is_fat_volume (const char * name, const char ** pPath)
1692{
1693 if (get_volume_info (name, pPath))
1694 return (volume_info.maxcomp == 12);
1695 return FALSE;
1696}
1697
1698/* Map filename to a legal 8.3 name if necessary. */
1699const char *
fbd6baed 1700map_w32_filename (const char * name, const char ** pPath)
480b0c5b
GV
1701{
1702 static char shortname[MAX_PATH];
1703 char * str = shortname;
1704 char c;
480b0c5b 1705 char * path;
76b3903d 1706 const char * save_name = name;
480b0c5b 1707
ca149beb
AI
1708 if (strlen (name) >= MAX_PATH)
1709 {
1710 /* Return a filename which will cause callers to fail. */
1711 strcpy (shortname, "?");
1712 return shortname;
1713 }
1714
a302c7ae 1715 if (is_fat_volume (name, (const char **)&path)) /* truncate to 8.3 */
95ed0025 1716 {
480b0c5b
GV
1717 register int left = 8; /* maximum number of chars in part */
1718 register int extn = 0; /* extension added? */
1719 register int dots = 2; /* maximum number of dots allowed */
1720
1721 while (name < path)
1722 *str++ = *name++; /* skip past UNC header */
1723
1724 while ((c = *name++))
1725 {
1726 switch ( c )
1727 {
1728 case '\\':
1729 case '/':
1730 *str++ = '\\';
1731 extn = 0; /* reset extension flags */
1732 dots = 2; /* max 2 dots */
1733 left = 8; /* max length 8 for main part */
1734 break;
1735 case ':':
1736 *str++ = ':';
1737 extn = 0; /* reset extension flags */
1738 dots = 2; /* max 2 dots */
1739 left = 8; /* max length 8 for main part */
1740 break;
1741 case '.':
1742 if ( dots )
1743 {
1744 /* Convert path components of the form .xxx to _xxx,
1745 but leave . and .. as they are. This allows .emacs
1746 to be read as _emacs, for example. */
1747
1748 if (! *name ||
1749 *name == '.' ||
1750 IS_DIRECTORY_SEP (*name))
1751 {
1752 *str++ = '.';
1753 dots--;
1754 }
1755 else
1756 {
1757 *str++ = '_';
1758 left--;
1759 dots = 0;
1760 }
1761 }
1762 else if ( !extn )
1763 {
1764 *str++ = '.';
1765 extn = 1; /* we've got an extension */
1766 left = 3; /* 3 chars in extension */
1767 }
1768 else
1769 {
1770 /* any embedded dots after the first are converted to _ */
1771 *str++ = '_';
1772 }
1773 break;
1774 case '~':
1775 case '#': /* don't lose these, they're important */
1776 if ( ! left )
1777 str[-1] = c; /* replace last character of part */
1778 /* FALLTHRU */
1779 default:
1780 if ( left )
1781 {
1782 *str++ = tolower (c); /* map to lower case (looks nicer) */
1783 left--;
1784 dots = 0; /* started a path component */
1785 }
1786 break;
1787 }
1788 }
1789 *str = '\0';
fc85cb29
RS
1790 }
1791 else
1792 {
1793 strcpy (shortname, name);
1794 unixtodos_filename (shortname);
95ed0025 1795 }
480b0c5b
GV
1796
1797 if (pPath)
76b3903d 1798 *pPath = shortname + (path - save_name);
480b0c5b 1799
fc85cb29 1800 return shortname;
480b0c5b
GV
1801}
1802
b3308d2e
KH
1803static int
1804is_exec (const char * name)
1805{
1806 char * p = strrchr (name, '.');
1807 return
1808 (p != NULL
1809 && (stricmp (p, ".exe") == 0 ||
1810 stricmp (p, ".com") == 0 ||
1811 stricmp (p, ".bat") == 0 ||
1812 stricmp (p, ".cmd") == 0));
1813}
1814
177c0ea7 1815/* Emulate the Unix directory procedures opendir, closedir,
76b3903d
GV
1816 and readdir. We can't use the procedures supplied in sysdep.c,
1817 so we provide them here. */
1818
1819struct direct dir_static; /* simulated directory contents */
1820static HANDLE dir_find_handle = INVALID_HANDLE_VALUE;
1821static int dir_is_fat;
1822static char dir_pathname[MAXPATHLEN+1];
1823static WIN32_FIND_DATA dir_find_data;
1824
9d3355d1
GV
1825/* Support shares on a network resource as subdirectories of a read-only
1826 root directory. */
1827static HANDLE wnet_enum_handle = INVALID_HANDLE_VALUE;
e0c181dd 1828HANDLE open_unc_volume (const char *);
9d3355d1
GV
1829char *read_unc_volume (HANDLE, char *, int);
1830void close_unc_volume (HANDLE);
1831
76b3903d
GV
1832DIR *
1833opendir (char *filename)
1834{
1835 DIR *dirp;
1836
1837 /* Opening is done by FindFirstFile. However, a read is inherent to
1838 this operation, so we defer the open until read time. */
1839
76b3903d
GV
1840 if (dir_find_handle != INVALID_HANDLE_VALUE)
1841 return NULL;
9d3355d1
GV
1842 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
1843 return NULL;
1844
1845 if (is_unc_volume (filename))
1846 {
1847 wnet_enum_handle = open_unc_volume (filename);
1848 if (wnet_enum_handle == INVALID_HANDLE_VALUE)
1849 return NULL;
1850 }
1851
1852 if (!(dirp = (DIR *) malloc (sizeof (DIR))))
1853 return NULL;
76b3903d
GV
1854
1855 dirp->dd_fd = 0;
1856 dirp->dd_loc = 0;
1857 dirp->dd_size = 0;
1858
1859 strncpy (dir_pathname, map_w32_filename (filename, NULL), MAXPATHLEN);
1860 dir_pathname[MAXPATHLEN] = '\0';
1861 dir_is_fat = is_fat_volume (filename, NULL);
1862
1863 return dirp;
1864}
1865
1866void
1867closedir (DIR *dirp)
1868{
1869 /* If we have a find-handle open, close it. */
1870 if (dir_find_handle != INVALID_HANDLE_VALUE)
1871 {
1872 FindClose (dir_find_handle);
1873 dir_find_handle = INVALID_HANDLE_VALUE;
1874 }
9d3355d1
GV
1875 else if (wnet_enum_handle != INVALID_HANDLE_VALUE)
1876 {
1877 close_unc_volume (wnet_enum_handle);
1878 wnet_enum_handle = INVALID_HANDLE_VALUE;
1879 }
76b3903d
GV
1880 xfree ((char *) dirp);
1881}
1882
1883struct direct *
1884readdir (DIR *dirp)
1885{
9d3355d1
GV
1886 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
1887 {
177c0ea7
JB
1888 if (!read_unc_volume (wnet_enum_handle,
1889 dir_find_data.cFileName,
9d3355d1
GV
1890 MAX_PATH))
1891 return NULL;
1892 }
76b3903d 1893 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
9d3355d1 1894 else if (dir_find_handle == INVALID_HANDLE_VALUE)
76b3903d
GV
1895 {
1896 char filename[MAXNAMLEN + 3];
1897 int ln;
1898
1899 strcpy (filename, dir_pathname);
1900 ln = strlen (filename) - 1;
1901 if (!IS_DIRECTORY_SEP (filename[ln]))
1902 strcat (filename, "\\");
1903 strcat (filename, "*");
1904
1905 dir_find_handle = FindFirstFile (filename, &dir_find_data);
1906
1907 if (dir_find_handle == INVALID_HANDLE_VALUE)
1908 return NULL;
1909 }
1910 else
1911 {
1912 if (!FindNextFile (dir_find_handle, &dir_find_data))
1913 return NULL;
1914 }
177c0ea7 1915
76b3903d
GV
1916 /* Emacs never uses this value, so don't bother making it match
1917 value returned by stat(). */
1918 dir_static.d_ino = 1;
177c0ea7 1919
76b3903d
GV
1920 dir_static.d_reclen = sizeof (struct direct) - MAXNAMLEN + 3 +
1921 dir_static.d_namlen - dir_static.d_namlen % 4;
177c0ea7 1922
76b3903d
GV
1923 dir_static.d_namlen = strlen (dir_find_data.cFileName);
1924 strcpy (dir_static.d_name, dir_find_data.cFileName);
1925 if (dir_is_fat)
1926 _strlwr (dir_static.d_name);
1927 else if (!NILP (Vw32_downcase_file_names))
1928 {
1929 register char *p;
1930 for (p = dir_static.d_name; *p; p++)
1931 if (*p >= 'a' && *p <= 'z')
1932 break;
1933 if (!*p)
1934 _strlwr (dir_static.d_name);
1935 }
177c0ea7 1936
76b3903d
GV
1937 return &dir_static;
1938}
1939
9d3355d1 1940HANDLE
e0c181dd 1941open_unc_volume (const char *path)
9d3355d1 1942{
177c0ea7 1943 NETRESOURCE nr;
9d3355d1
GV
1944 HANDLE henum;
1945 int result;
1946
177c0ea7
JB
1947 nr.dwScope = RESOURCE_GLOBALNET;
1948 nr.dwType = RESOURCETYPE_DISK;
1949 nr.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
1950 nr.dwUsage = RESOURCEUSAGE_CONTAINER;
1951 nr.lpLocalName = NULL;
6e602566 1952 nr.lpRemoteName = (LPSTR)map_w32_filename (path, NULL);
177c0ea7
JB
1953 nr.lpComment = NULL;
1954 nr.lpProvider = NULL;
9d3355d1 1955
177c0ea7 1956 result = WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
9d3355d1
GV
1957 RESOURCEUSAGE_CONNECTABLE, &nr, &henum);
1958
1959 if (result == NO_ERROR)
1960 return henum;
1961 else
1962 return INVALID_HANDLE_VALUE;
1963}
1964
1965char *
1966read_unc_volume (HANDLE henum, char *readbuf, int size)
1967{
a302c7ae 1968 DWORD count;
9d3355d1 1969 int result;
a302c7ae 1970 DWORD bufsize = 512;
9d3355d1
GV
1971 char *buffer;
1972 char *ptr;
1973
1974 count = 1;
1975 buffer = alloca (bufsize);
1976 result = WNetEnumResource (wnet_enum_handle, &count, buffer, &bufsize);
1977 if (result != NO_ERROR)
1978 return NULL;
1979
1980 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
1981 ptr = ((LPNETRESOURCE) buffer)->lpRemoteName;
1982 ptr += 2;
1983 while (*ptr && !IS_DIRECTORY_SEP (*ptr)) ptr++;
1984 ptr++;
1985
1986 strncpy (readbuf, ptr, size);
1987 return readbuf;
1988}
1989
1990void
1991close_unc_volume (HANDLE henum)
1992{
1993 if (henum != INVALID_HANDLE_VALUE)
1994 WNetCloseEnum (henum);
1995}
1996
1997DWORD
e0c181dd 1998unc_volume_file_attributes (const char *path)
9d3355d1
GV
1999{
2000 HANDLE henum;
2001 DWORD attrs;
2002
2003 henum = open_unc_volume (path);
2004 if (henum == INVALID_HANDLE_VALUE)
2005 return -1;
2006
2007 attrs = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY;
2008
2009 close_unc_volume (henum);
2010
2011 return attrs;
2012}
2013
302d7d54
JR
2014/* Ensure a network connection is authenticated. */
2015static void
2016logon_network_drive (const char *path)
2017{
2018 NETRESOURCE resource;
2019 char share[MAX_PATH];
2020 int i, n_slashes;
2021
2022 /* Only logon to networked drives. */
2023 if (!IS_DIRECTORY_SEP (path[0]) || !IS_DIRECTORY_SEP (path[1]))
2024 return;
2025 n_slashes = 2;
2026 strncpy (share, path, MAX_PATH);
2027 /* Truncate to just server and share name. */
2028 for (i = 2; i < MAX_PATH; i++)
2029 {
2030 if (IS_DIRECTORY_SEP (share[i]) && ++n_slashes > 3)
2031 {
2032 share[i] = '\0';
2033 break;
2034 }
2035 }
2036
2037 resource.dwType = RESOURCETYPE_DISK;
2038 resource.lpLocalName = NULL;
2039 resource.lpRemoteName = share;
2040 resource.lpProvider = NULL;
2041
2042 WNetAddConnection2 (&resource, NULL, NULL, CONNECT_INTERACTIVE);
2043}
480b0c5b
GV
2044
2045/* Shadow some MSVC runtime functions to map requests for long filenames
2046 to reasonable short names if necessary. This was originally added to
177c0ea7 2047 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
480b0c5b
GV
2048 long file names. */
2049
2050int
2051sys_access (const char * path, int mode)
2052{
b3308d2e
KH
2053 DWORD attributes;
2054
2055 /* MSVC implementation doesn't recognize D_OK. */
2056 path = map_w32_filename (path, NULL);
9d3355d1
GV
2057 if (is_unc_volume (path))
2058 {
2059 attributes = unc_volume_file_attributes (path);
2060 if (attributes == -1) {
2061 errno = EACCES;
2062 return -1;
2063 }
2064 }
2065 else if ((attributes = GetFileAttributes (path)) == -1)
b3308d2e
KH
2066 {
2067 /* Should try mapping GetLastError to errno; for now just indicate
2068 that path doesn't exist. */
2069 errno = EACCES;
2070 return -1;
2071 }
2072 if ((mode & X_OK) != 0 && !is_exec (path))
2073 {
2074 errno = EACCES;
2075 return -1;
2076 }
2077 if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0)
2078 {
2079 errno = EACCES;
2080 return -1;
2081 }
2082 if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
2083 {
2084 errno = EACCES;
2085 return -1;
2086 }
2087 return 0;
480b0c5b
GV
2088}
2089
2090int
2091sys_chdir (const char * path)
2092{
fbd6baed 2093 return _chdir (map_w32_filename (path, NULL));
480b0c5b
GV
2094}
2095
2096int
2097sys_chmod (const char * path, int mode)
2098{
fbd6baed 2099 return _chmod (map_w32_filename (path, NULL), mode);
480b0c5b
GV
2100}
2101
2d5ab4bf
EZ
2102int
2103sys_chown (const char *path, uid_t owner, gid_t group)
2104{
2105 if (sys_chmod (path, _S_IREAD) == -1) /* check if file exists */
2106 return -1;
2107 return 0;
2108}
2109
480b0c5b
GV
2110int
2111sys_creat (const char * path, int mode)
2112{
fbd6baed 2113 return _creat (map_w32_filename (path, NULL), mode);
480b0c5b
GV
2114}
2115
2116FILE *
2117sys_fopen(const char * path, const char * mode)
2118{
2119 int fd;
2120 int oflag;
2121 const char * mode_save = mode;
2122
2123 /* Force all file handles to be non-inheritable. This is necessary to
2124 ensure child processes don't unwittingly inherit handles that might
2125 prevent future file access. */
2126
2127 if (mode[0] == 'r')
2128 oflag = O_RDONLY;
2129 else if (mode[0] == 'w' || mode[0] == 'a')
2130 oflag = O_WRONLY | O_CREAT | O_TRUNC;
95ed0025 2131 else
480b0c5b
GV
2132 return NULL;
2133
2134 /* Only do simplistic option parsing. */
2135 while (*++mode)
2136 if (mode[0] == '+')
2137 {
2138 oflag &= ~(O_RDONLY | O_WRONLY);
2139 oflag |= O_RDWR;
2140 }
2141 else if (mode[0] == 'b')
2142 {
2143 oflag &= ~O_TEXT;
2144 oflag |= O_BINARY;
2145 }
2146 else if (mode[0] == 't')
2147 {
2148 oflag &= ~O_BINARY;
2149 oflag |= O_TEXT;
2150 }
2151 else break;
2152
fbd6baed 2153 fd = _open (map_w32_filename (path, NULL), oflag | _O_NOINHERIT, 0644);
480b0c5b
GV
2154 if (fd < 0)
2155 return NULL;
2156
76b3903d 2157 return _fdopen (fd, mode_save);
95ed0025 2158}
480b0c5b 2159
76b3903d 2160/* This only works on NTFS volumes, but is useful to have. */
480b0c5b 2161int
76b3903d 2162sys_link (const char * old, const char * new)
480b0c5b 2163{
76b3903d
GV
2164 HANDLE fileh;
2165 int result = -1;
2166 char oldname[MAX_PATH], newname[MAX_PATH];
2167
2168 if (old == NULL || new == NULL)
2169 {
2170 errno = ENOENT;
2171 return -1;
2172 }
2173
2174 strcpy (oldname, map_w32_filename (old, NULL));
2175 strcpy (newname, map_w32_filename (new, NULL));
2176
2177 fileh = CreateFile (oldname, 0, 0, NULL, OPEN_EXISTING,
2178 FILE_FLAG_BACKUP_SEMANTICS, NULL);
2179 if (fileh != INVALID_HANDLE_VALUE)
2180 {
2181 int wlen;
2182
2183 /* Confusingly, the "alternate" stream name field does not apply
2184 when restoring a hard link, and instead contains the actual
2185 stream data for the link (ie. the name of the link to create).
2186 The WIN32_STREAM_ID structure before the cStreamName field is
2187 the stream header, which is then immediately followed by the
2188 stream data. */
2189
2190 struct {
2191 WIN32_STREAM_ID wid;
2192 WCHAR wbuffer[MAX_PATH]; /* extra space for link name */
2193 } data;
2194
2195 wlen = MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, newname, -1,
2196 data.wid.cStreamName, MAX_PATH);
2197 if (wlen > 0)
2198 {
2199 LPVOID context = NULL;
2200 DWORD wbytes = 0;
2201
2202 data.wid.dwStreamId = BACKUP_LINK;
2203 data.wid.dwStreamAttributes = 0;
2204 data.wid.Size.LowPart = wlen * sizeof(WCHAR);
2205 data.wid.Size.HighPart = 0;
2206 data.wid.dwStreamNameSize = 0;
2207
2208 if (BackupWrite (fileh, (LPBYTE)&data,
2209 offsetof (WIN32_STREAM_ID, cStreamName)
2210 + data.wid.Size.LowPart,
2211 &wbytes, FALSE, FALSE, &context)
2212 && BackupWrite (fileh, NULL, 0, &wbytes, TRUE, FALSE, &context))
2213 {
2214 /* succeeded */
2215 result = 0;
2216 }
2217 else
2218 {
2219 /* Should try mapping GetLastError to errno; for now just
2220 indicate a general error (eg. links not supported). */
2221 errno = EINVAL; // perhaps EMLINK?
2222 }
2223 }
2224
2225 CloseHandle (fileh);
2226 }
2227 else
2228 errno = ENOENT;
2229
2230 return result;
480b0c5b
GV
2231}
2232
2233int
2234sys_mkdir (const char * path)
2235{
fbd6baed 2236 return _mkdir (map_w32_filename (path, NULL));
480b0c5b
GV
2237}
2238
9d1778b1
RS
2239/* Because of long name mapping issues, we need to implement this
2240 ourselves. Also, MSVC's _mktemp returns NULL when it can't generate
2241 a unique name, instead of setting the input template to an empty
2242 string.
2243
2244 Standard algorithm seems to be use pid or tid with a letter on the
2245 front (in place of the 6 X's) and cycle through the letters to find a
2246 unique name. We extend that to allow any reasonable character as the
2247 first of the 6 X's. */
480b0c5b
GV
2248char *
2249sys_mktemp (char * template)
2250{
9d1778b1
RS
2251 char * p;
2252 int i;
2253 unsigned uid = GetCurrentThreadId ();
2254 static char first_char[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
2255
2256 if (template == NULL)
2257 return NULL;
2258 p = template + strlen (template);
2259 i = 5;
2260 /* replace up to the last 5 X's with uid in decimal */
2261 while (--p >= template && p[0] == 'X' && --i >= 0)
2262 {
2263 p[0] = '0' + uid % 10;
2264 uid /= 10;
2265 }
2266
2267 if (i < 0 && p[0] == 'X')
2268 {
2269 i = 0;
2270 do
2271 {
2272 int save_errno = errno;
2273 p[0] = first_char[i];
2274 if (sys_access (template, 0) < 0)
2275 {
2276 errno = save_errno;
2277 return template;
2278 }
2279 }
2280 while (++i < sizeof (first_char));
2281 }
2282
2283 /* Template is badly formed or else we can't generate a unique name,
2284 so return empty string */
2285 template[0] = 0;
2286 return template;
480b0c5b
GV
2287}
2288
2289int
2290sys_open (const char * path, int oflag, int mode)
2291{
302f0b29
GM
2292 const char* mpath = map_w32_filename (path, NULL);
2293 /* Try to open file without _O_CREAT, to be able to write to hidden
2294 and system files. Force all file handles to be
2295 non-inheritable. */
2296 int res = _open (mpath, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
2297 if (res >= 0)
2298 return res;
2299 return _open (mpath, oflag | _O_NOINHERIT, mode);
480b0c5b
GV
2300}
2301
2302int
2303sys_rename (const char * oldname, const char * newname)
2304{
cfb5e855 2305 BOOL result;
b3308d2e 2306 char temp[MAX_PATH];
480b0c5b 2307
e9e23e23 2308 /* MoveFile on Windows 95 doesn't correctly change the short file name
5162ffce
MB
2309 alias in a number of circumstances (it is not easy to predict when
2310 just by looking at oldname and newname, unfortunately). In these
2311 cases, renaming through a temporary name avoids the problem.
2312
e9e23e23 2313 A second problem on Windows 95 is that renaming through a temp name when
5162ffce
MB
2314 newname is uppercase fails (the final long name ends up in
2315 lowercase, although the short alias might be uppercase) UNLESS the
2316 long temp name is not 8.3.
2317
e9e23e23 2318 So, on Windows 95 we always rename through a temp name, and we make sure
5162ffce 2319 the temp name has a long extension to ensure correct renaming. */
480b0c5b 2320
fbd6baed 2321 strcpy (temp, map_w32_filename (oldname, NULL));
480b0c5b 2322
76b3903d 2323 if (os_subtype == OS_WIN95)
480b0c5b 2324 {
b3308d2e 2325 char * o;
480b0c5b 2326 char * p;
b3308d2e
KH
2327 int i = 0;
2328
2329 oldname = map_w32_filename (oldname, NULL);
2330 if (o = strrchr (oldname, '\\'))
2331 o++;
2332 else
2333 o = (char *) oldname;
480b0c5b 2334
480b0c5b
GV
2335 if (p = strrchr (temp, '\\'))
2336 p++;
2337 else
2338 p = temp;
b3308d2e
KH
2339
2340 do
2341 {
2342 /* Force temp name to require a manufactured 8.3 alias - this
2343 seems to make the second rename work properly. */
f313ee82 2344 sprintf (p, "_.%s.%u", o, i);
b3308d2e 2345 i++;
58f0cb7e 2346 result = rename (oldname, temp);
b3308d2e
KH
2347 }
2348 /* This loop must surely terminate! */
cfb5e855 2349 while (result < 0 && errno == EEXIST);
58f0cb7e 2350 if (result < 0)
480b0c5b
GV
2351 return -1;
2352 }
2353
2354 /* Emulate Unix behaviour - newname is deleted if it already exists
5162ffce 2355 (at least if it is a file; don't do this for directories).
76b3903d 2356
b3308d2e
KH
2357 Since we mustn't do this if we are just changing the case of the
2358 file name (we would end up deleting the file we are trying to
2359 rename!), we let rename detect if the destination file already
2360 exists - that way we avoid the possible pitfalls of trying to
2361 determine ourselves whether two names really refer to the same
2362 file, which is not always possible in the general case. (Consider
2363 all the permutations of shared or subst'd drives, etc.) */
2364
2365 newname = map_w32_filename (newname, NULL);
eb9ea53f 2366 result = rename (temp, newname);
b3308d2e
KH
2367
2368 if (result < 0
cfb5e855 2369 && errno == EEXIST
b3308d2e
KH
2370 && _chmod (newname, 0666) == 0
2371 && _unlink (newname) == 0)
2372 result = rename (temp, newname);
480b0c5b 2373
eb9ea53f 2374 return result;
480b0c5b
GV
2375}
2376
2377int
2378sys_rmdir (const char * path)
2379{
fbd6baed 2380 return _rmdir (map_w32_filename (path, NULL));
480b0c5b
GV
2381}
2382
2383int
2384sys_unlink (const char * path)
2385{
16bb7578
GV
2386 path = map_w32_filename (path, NULL);
2387
2388 /* On Unix, unlink works without write permission. */
2389 _chmod (path, 0666);
2390 return _unlink (path);
480b0c5b
GV
2391}
2392
2393static FILETIME utc_base_ft;
2394static long double utc_base;
2395static int init = 0;
2396
2397static time_t
2398convert_time (FILETIME ft)
2399{
2400 long double ret;
2401
2402 if (!init)
2403 {
2404 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
2405 SYSTEMTIME st;
2406
2407 st.wYear = 1970;
2408 st.wMonth = 1;
2409 st.wDay = 1;
2410 st.wHour = 0;
2411 st.wMinute = 0;
2412 st.wSecond = 0;
2413 st.wMilliseconds = 0;
2414
2415 SystemTimeToFileTime (&st, &utc_base_ft);
2416 utc_base = (long double) utc_base_ft.dwHighDateTime
69b72317 2417 * 4096.0L * 1024.0L * 1024.0L + utc_base_ft.dwLowDateTime;
480b0c5b
GV
2418 init = 1;
2419 }
2420
2421 if (CompareFileTime (&ft, &utc_base_ft) < 0)
2422 return 0;
2423
69b72317
EZ
2424 ret = (long double) ft.dwHighDateTime
2425 * 4096.0L * 1024.0L * 1024.0L + ft.dwLowDateTime;
480b0c5b 2426 ret -= utc_base;
69b72317 2427 return (time_t) (ret * 1e-7L);
480b0c5b
GV
2428}
2429
480b0c5b
GV
2430void
2431convert_from_time_t (time_t time, FILETIME * pft)
2432{
2433 long double tmp;
2434
2435 if (!init)
2436 {
2437 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
2438 SYSTEMTIME st;
2439
2440 st.wYear = 1970;
2441 st.wMonth = 1;
2442 st.wDay = 1;
2443 st.wHour = 0;
2444 st.wMinute = 0;
2445 st.wSecond = 0;
2446 st.wMilliseconds = 0;
2447
2448 SystemTimeToFileTime (&st, &utc_base_ft);
2449 utc_base = (long double) utc_base_ft.dwHighDateTime
2450 * 4096 * 1024 * 1024 + utc_base_ft.dwLowDateTime;
2451 init = 1;
2452 }
2453
2454 /* time in 100ns units since 1-Jan-1601 */
2455 tmp = (long double) time * 1e7 + utc_base;
2456 pft->dwHighDateTime = (DWORD) (tmp / (4096.0 * 1024 * 1024));
16bb7578 2457 pft->dwLowDateTime = (DWORD) (tmp - (4096.0 * 1024 * 1024) * pft->dwHighDateTime);
480b0c5b 2458}
480b0c5b 2459
76b3903d
GV
2460#if 0
2461/* No reason to keep this; faking inode values either by hashing or even
2462 using the file index from GetInformationByHandle, is not perfect and
2463 so by default Emacs doesn't use the inode values on Windows.
2464 Instead, we now determine file-truename correctly (except for
2465 possible drive aliasing etc). */
2466
2467/* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
480b0c5b 2468static unsigned
76b3903d 2469hashval (const unsigned char * str)
480b0c5b
GV
2470{
2471 unsigned h = 0;
480b0c5b
GV
2472 while (*str)
2473 {
2474 h = (h << 4) + *str++;
76b3903d 2475 h ^= (h >> 28);
480b0c5b
GV
2476 }
2477 return h;
2478}
2479
2480/* Return the hash value of the canonical pathname, excluding the
2481 drive/UNC header, to get a hopefully unique inode number. */
76b3903d 2482static DWORD
480b0c5b
GV
2483generate_inode_val (const char * name)
2484{
2485 char fullname[ MAX_PATH ];
2486 char * p;
2487 unsigned hash;
2488
76b3903d
GV
2489 /* Get the truly canonical filename, if it exists. (Note: this
2490 doesn't resolve aliasing due to subst commands, or recognise hard
2491 links. */
2492 if (!w32_get_long_filename ((char *)name, fullname, MAX_PATH))
2493 abort ();
2494
2495 parse_root (fullname, &p);
fbd6baed 2496 /* Normal W32 filesystems are still case insensitive. */
480b0c5b 2497 _strlwr (p);
76b3903d 2498 return hashval (p);
480b0c5b
GV
2499}
2500
76b3903d
GV
2501#endif
2502
480b0c5b
GV
2503/* MSVC stat function can't cope with UNC names and has other bugs, so
2504 replace it with our own. This also allows us to calculate consistent
2505 inode values without hacks in the main Emacs code. */
2506int
2507stat (const char * path, struct stat * buf)
2508{
eb9ea53f 2509 char *name, *r;
480b0c5b
GV
2510 WIN32_FIND_DATA wfd;
2511 HANDLE fh;
76b3903d 2512 DWORD fake_inode;
480b0c5b
GV
2513 int permission;
2514 int len;
2515 int rootdir = FALSE;
2516
2517 if (path == NULL || buf == NULL)
2518 {
2519 errno = EFAULT;
2520 return -1;
2521 }
2522
fbd6baed 2523 name = (char *) map_w32_filename (path, &path);
22189f79
EZ
2524 /* Must be valid filename, no wild cards or other invalid
2525 characters. We use _mbspbrk to support multibyte strings that
2526 might look to strpbrk as if they included literal *, ?, and other
2527 characters mentioned below that are disallowed by Windows
2528 filesystems. */
2529 if (_mbspbrk (name, "*?|<>\""))
480b0c5b
GV
2530 {
2531 errno = ENOENT;
2532 return -1;
2533 }
2534
eb9ea53f
GV
2535 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
2536 r = IS_DEVICE_SEP (name[1]) ? &name[2] : name;
2537 if (IS_DIRECTORY_SEP (r[0]) && r[1] == '.' && r[2] == '.' && r[3] == '\0')
2538 {
2539 r[1] = r[2] = '\0';
2540 }
2541
480b0c5b
GV
2542 /* Remove trailing directory separator, unless name is the root
2543 directory of a drive or UNC volume in which case ensure there
2544 is a trailing separator. */
2545 len = strlen (name);
2546 rootdir = (path >= name + len - 1
2547 && (IS_DIRECTORY_SEP (*path) || *path == 0));
2548 name = strcpy (alloca (len + 2), name);
2549
9d3355d1
GV
2550 if (is_unc_volume (name))
2551 {
2552 DWORD attrs = unc_volume_file_attributes (name);
2553
2554 if (attrs == -1)
2555 return -1;
2556
2557 memset (&wfd, 0, sizeof (wfd));
2558 wfd.dwFileAttributes = attrs;
2559 wfd.ftCreationTime = utc_base_ft;
2560 wfd.ftLastAccessTime = utc_base_ft;
2561 wfd.ftLastWriteTime = utc_base_ft;
2562 strcpy (wfd.cFileName, name);
2563 }
2564 else if (rootdir)
480b0c5b
GV
2565 {
2566 if (!IS_DIRECTORY_SEP (name[len-1]))
2567 strcat (name, "\\");
2568 if (GetDriveType (name) < 2)
2569 {
2570 errno = ENOENT;
2571 return -1;
2572 }
2573 memset (&wfd, 0, sizeof (wfd));
2574 wfd.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
2575 wfd.ftCreationTime = utc_base_ft;
2576 wfd.ftLastAccessTime = utc_base_ft;
2577 wfd.ftLastWriteTime = utc_base_ft;
2578 strcpy (wfd.cFileName, name);
2579 }
2580 else
2581 {
2582 if (IS_DIRECTORY_SEP (name[len-1]))
2583 name[len - 1] = 0;
76b3903d
GV
2584
2585 /* (This is hacky, but helps when doing file completions on
2586 network drives.) Optimize by using information available from
2587 active readdir if possible. */
b19cc00c
GV
2588 len = strlen (dir_pathname);
2589 if (IS_DIRECTORY_SEP (dir_pathname[len-1]))
2590 len--;
76b3903d 2591 if (dir_find_handle != INVALID_HANDLE_VALUE
b19cc00c 2592 && strnicmp (name, dir_pathname, len) == 0
76b3903d
GV
2593 && IS_DIRECTORY_SEP (name[len])
2594 && stricmp (name + len + 1, dir_static.d_name) == 0)
480b0c5b 2595 {
76b3903d
GV
2596 /* This was the last entry returned by readdir. */
2597 wfd = dir_find_data;
2598 }
2599 else
2600 {
513feaa5 2601 logon_network_drive (name);
302d7d54 2602
76b3903d
GV
2603 fh = FindFirstFile (name, &wfd);
2604 if (fh == INVALID_HANDLE_VALUE)
2605 {
2606 errno = ENOENT;
2607 return -1;
2608 }
2609 FindClose (fh);
480b0c5b 2610 }
480b0c5b
GV
2611 }
2612
93e0f0da
JR
2613 if (!NILP (Vw32_get_true_file_attributes)
2614 /* No access rights required to get info. */
2615 && (fh = CreateFile (name, 0, 0, NULL, OPEN_EXISTING,
2616 FILE_FLAG_BACKUP_SEMANTICS, NULL))
2617 != INVALID_HANDLE_VALUE)
480b0c5b 2618 {
480b0c5b 2619 /* This is more accurate in terms of gettting the correct number
aa5ee2a3 2620 of links, but is quite slow (it is noticeable when Emacs is
480b0c5b
GV
2621 making a list of file name completions). */
2622 BY_HANDLE_FILE_INFORMATION info;
2623
480b0c5b
GV
2624 if (GetFileInformationByHandle (fh, &info))
2625 {
480b0c5b 2626 buf->st_nlink = info.nNumberOfLinks;
76b3903d
GV
2627 /* Might as well use file index to fake inode values, but this
2628 is not guaranteed to be unique unless we keep a handle open
2629 all the time (even then there are situations where it is
2630 not unique). Reputedly, there are at most 48 bits of info
2631 (on NTFS, presumably less on FAT). */
2632 fake_inode = info.nFileIndexLow ^ info.nFileIndexHigh;
480b0c5b
GV
2633 }
2634 else
2635 {
01f31dfb
AI
2636 buf->st_nlink = 1;
2637 fake_inode = 0;
2638 }
2639
93e0f0da 2640 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
01f31dfb 2641 {
93e0f0da
JR
2642 buf->st_mode = _S_IFDIR;
2643 }
2644 else
2645 {
2646 switch (GetFileType (fh))
2647 {
2648 case FILE_TYPE_DISK:
2649 buf->st_mode = _S_IFREG;
2650 break;
2651 case FILE_TYPE_PIPE:
2652 buf->st_mode = _S_IFIFO;
2653 break;
2654 case FILE_TYPE_CHAR:
2655 case FILE_TYPE_UNKNOWN:
2656 default:
2657 buf->st_mode = _S_IFCHR;
2658 }
480b0c5b 2659 }
01f31dfb 2660 CloseHandle (fh);
76b3903d
GV
2661 }
2662 else
2663 {
2664 /* Don't bother to make this information more accurate. */
93e0f0da 2665 buf->st_mode = (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ?
bc5fdfc7 2666 _S_IFDIR : _S_IFREG;
480b0c5b 2667 buf->st_nlink = 1;
76b3903d
GV
2668 fake_inode = 0;
2669 }
2670
2671#if 0
2672 /* Not sure if there is any point in this. */
2673 if (!NILP (Vw32_generate_fake_inodes))
2674 fake_inode = generate_inode_val (name);
2675 else if (fake_inode == 0)
2676 {
2677 /* For want of something better, try to make everything unique. */
2678 static DWORD gen_num = 0;
2679 fake_inode = ++gen_num;
480b0c5b 2680 }
76b3903d
GV
2681#endif
2682
2683 /* MSVC defines _ino_t to be short; other libc's might not. */
2684 if (sizeof (buf->st_ino) == 2)
2685 buf->st_ino = fake_inode ^ (fake_inode >> 16);
2686 else
2687 buf->st_ino = fake_inode;
480b0c5b
GV
2688
2689 /* consider files to belong to current user */
2690 buf->st_uid = the_passwd.pw_uid;
2691 buf->st_gid = the_passwd.pw_gid;
2692
fbd6baed 2693 /* volume_info is set indirectly by map_w32_filename */
480b0c5b
GV
2694 buf->st_dev = volume_info.serialnum;
2695 buf->st_rdev = volume_info.serialnum;
2696
480b0c5b
GV
2697
2698 buf->st_size = wfd.nFileSizeLow;
2699
2700 /* Convert timestamps to Unix format. */
2701 buf->st_mtime = convert_time (wfd.ftLastWriteTime);
2702 buf->st_atime = convert_time (wfd.ftLastAccessTime);
2703 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
2704 buf->st_ctime = convert_time (wfd.ftCreationTime);
2705 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
2706
2707 /* determine rwx permissions */
2708 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
2709 permission = _S_IREAD;
2710 else
2711 permission = _S_IREAD | _S_IWRITE;
177c0ea7 2712
480b0c5b
GV
2713 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
2714 permission |= _S_IEXEC;
b3308d2e
KH
2715 else if (is_exec (name))
2716 permission |= _S_IEXEC;
480b0c5b
GV
2717
2718 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
2719
2720 return 0;
2721}
2722
16bb7578
GV
2723/* Provide fstat and utime as well as stat for consistent handling of
2724 file timestamps. */
2725int
2726fstat (int desc, struct stat * buf)
2727{
2728 HANDLE fh = (HANDLE) _get_osfhandle (desc);
2729 BY_HANDLE_FILE_INFORMATION info;
2730 DWORD fake_inode;
2731 int permission;
2732
2733 switch (GetFileType (fh) & ~FILE_TYPE_REMOTE)
2734 {
2735 case FILE_TYPE_DISK:
2736 buf->st_mode = _S_IFREG;
2737 if (!GetFileInformationByHandle (fh, &info))
2738 {
2739 errno = EACCES;
2740 return -1;
2741 }
2742 break;
2743 case FILE_TYPE_PIPE:
2744 buf->st_mode = _S_IFIFO;
2745 goto non_disk;
2746 case FILE_TYPE_CHAR:
2747 case FILE_TYPE_UNKNOWN:
2748 default:
2749 buf->st_mode = _S_IFCHR;
2750 non_disk:
2751 memset (&info, 0, sizeof (info));
2752 info.dwFileAttributes = 0;
2753 info.ftCreationTime = utc_base_ft;
2754 info.ftLastAccessTime = utc_base_ft;
2755 info.ftLastWriteTime = utc_base_ft;
2756 }
2757
2758 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
16bb7578 2759 buf->st_mode = _S_IFDIR;
93e0f0da
JR
2760
2761 buf->st_nlink = info.nNumberOfLinks;
2762 /* Might as well use file index to fake inode values, but this
2763 is not guaranteed to be unique unless we keep a handle open
2764 all the time (even then there are situations where it is
2765 not unique). Reputedly, there are at most 48 bits of info
2766 (on NTFS, presumably less on FAT). */
2767 fake_inode = info.nFileIndexLow ^ info.nFileIndexHigh;
16bb7578
GV
2768
2769 /* MSVC defines _ino_t to be short; other libc's might not. */
2770 if (sizeof (buf->st_ino) == 2)
2771 buf->st_ino = fake_inode ^ (fake_inode >> 16);
2772 else
2773 buf->st_ino = fake_inode;
2774
2775 /* consider files to belong to current user */
248c21c5
EZ
2776 buf->st_uid = the_passwd.pw_uid;
2777 buf->st_gid = the_passwd.pw_gid;
16bb7578
GV
2778
2779 buf->st_dev = info.dwVolumeSerialNumber;
2780 buf->st_rdev = info.dwVolumeSerialNumber;
2781
2782 buf->st_size = info.nFileSizeLow;
2783
2784 /* Convert timestamps to Unix format. */
2785 buf->st_mtime = convert_time (info.ftLastWriteTime);
2786 buf->st_atime = convert_time (info.ftLastAccessTime);
2787 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
2788 buf->st_ctime = convert_time (info.ftCreationTime);
2789 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
2790
2791 /* determine rwx permissions */
2792 if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
2793 permission = _S_IREAD;
2794 else
2795 permission = _S_IREAD | _S_IWRITE;
177c0ea7 2796
16bb7578
GV
2797 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
2798 permission |= _S_IEXEC;
2799 else
2800 {
2801#if 0 /* no way of knowing the filename */
2802 char * p = strrchr (name, '.');
2803 if (p != NULL &&
2804 (stricmp (p, ".exe") == 0 ||
2805 stricmp (p, ".com") == 0 ||
2806 stricmp (p, ".bat") == 0 ||
2807 stricmp (p, ".cmd") == 0))
2808 permission |= _S_IEXEC;
2809#endif
2810 }
2811
2812 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
2813
2814 return 0;
2815}
2816
2817int
2818utime (const char *name, struct utimbuf *times)
2819{
2820 struct utimbuf deftime;
2821 HANDLE fh;
2822 FILETIME mtime;
2823 FILETIME atime;
2824
2825 if (times == NULL)
2826 {
2827 deftime.modtime = deftime.actime = time (NULL);
2828 times = &deftime;
2829 }
2830
2831 /* Need write access to set times. */
2832 fh = CreateFile (name, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
2833 0, OPEN_EXISTING, 0, NULL);
2834 if (fh)
2835 {
2836 convert_from_time_t (times->actime, &atime);
2837 convert_from_time_t (times->modtime, &mtime);
2838 if (!SetFileTime (fh, NULL, &atime, &mtime))
2839 {
2840 CloseHandle (fh);
2841 errno = EACCES;
2842 return -1;
2843 }
2844 CloseHandle (fh);
2845 }
2846 else
2847 {
2848 errno = EINVAL;
2849 return -1;
2850 }
2851 return 0;
2852}
2853
480b0c5b
GV
2854#ifdef HAVE_SOCKETS
2855
2856/* Wrappers for winsock functions to map between our file descriptors
2857 and winsock's handles; also set h_errno for convenience.
2858
2859 To allow Emacs to run on systems which don't have winsock support
2860 installed, we dynamically link to winsock on startup if present, and
2861 otherwise provide the minimum necessary functionality
2862 (eg. gethostname). */
2863
2864/* function pointers for relevant socket functions */
2865int (PASCAL *pfn_WSAStartup) (WORD wVersionRequired, LPWSADATA lpWSAData);
2866void (PASCAL *pfn_WSASetLastError) (int iError);
2867int (PASCAL *pfn_WSAGetLastError) (void);
26fb7bc4 2868int (PASCAL *pfn_WSAEventSelect) (SOCKET s, HANDLE hEventObject, long lNetworkEvents);
64570b36
KS
2869HANDLE (PASCAL *pfn_WSACreateEvent) (void);
2870int (PASCAL *pfn_WSACloseEvent) (HANDLE hEvent);
480b0c5b
GV
2871int (PASCAL *pfn_socket) (int af, int type, int protocol);
2872int (PASCAL *pfn_bind) (SOCKET s, const struct sockaddr *addr, int namelen);
2873int (PASCAL *pfn_connect) (SOCKET s, const struct sockaddr *addr, int namelen);
2874int (PASCAL *pfn_ioctlsocket) (SOCKET s, long cmd, u_long *argp);
2875int (PASCAL *pfn_recv) (SOCKET s, char * buf, int len, int flags);
2876int (PASCAL *pfn_send) (SOCKET s, const char * buf, int len, int flags);
2877int (PASCAL *pfn_closesocket) (SOCKET s);
2878int (PASCAL *pfn_shutdown) (SOCKET s, int how);
2879int (PASCAL *pfn_WSACleanup) (void);
2880
2881u_short (PASCAL *pfn_htons) (u_short hostshort);
2882u_short (PASCAL *pfn_ntohs) (u_short netshort);
2883unsigned long (PASCAL *pfn_inet_addr) (const char * cp);
2884int (PASCAL *pfn_gethostname) (char * name, int namelen);
2885struct hostent * (PASCAL *pfn_gethostbyname) (const char * name);
2886struct servent * (PASCAL *pfn_getservbyname) (const char * name, const char * proto);
ecd270eb 2887int (PASCAL *pfn_getpeername) (SOCKET s, struct sockaddr *addr, int * namelen);
962955c5
JR
2888int (PASCAL *pfn_setsockopt) (SOCKET s, int level, int optname,
2889 const char * optval, int optlen);
2890int (PASCAL *pfn_listen) (SOCKET s, int backlog);
2891int (PASCAL *pfn_getsockname) (SOCKET s, struct sockaddr * name,
2892 int * namelen);
2893SOCKET (PASCAL *pfn_accept) (SOCKET s, struct sockaddr * addr, int * addrlen);
2894int (PASCAL *pfn_recvfrom) (SOCKET s, char * buf, int len, int flags,
2895 struct sockaddr * from, int * fromlen);
2896int (PASCAL *pfn_sendto) (SOCKET s, const char * buf, int len, int flags,
2897 const struct sockaddr * to, int tolen);
2898
f1614061
RS
2899/* SetHandleInformation is only needed to make sockets non-inheritable. */
2900BOOL (WINAPI *pfn_SetHandleInformation) (HANDLE object, DWORD mask, DWORD flags);
2901#ifndef HANDLE_FLAG_INHERIT
2902#define HANDLE_FLAG_INHERIT 1
2903#endif
480b0c5b 2904
f249a012
RS
2905HANDLE winsock_lib;
2906static int winsock_inuse;
480b0c5b 2907
f249a012 2908BOOL
480b0c5b
GV
2909term_winsock (void)
2910{
f249a012 2911 if (winsock_lib != NULL && winsock_inuse == 0)
480b0c5b 2912 {
f249a012
RS
2913 /* Not sure what would cause WSAENETDOWN, or even if it can happen
2914 after WSAStartup returns successfully, but it seems reasonable
2915 to allow unloading winsock anyway in that case. */
2916 if (pfn_WSACleanup () == 0 ||
2917 pfn_WSAGetLastError () == WSAENETDOWN)
2918 {
2919 if (FreeLibrary (winsock_lib))
2920 winsock_lib = NULL;
2921 return TRUE;
2922 }
480b0c5b 2923 }
f249a012 2924 return FALSE;
480b0c5b
GV
2925}
2926
f249a012
RS
2927BOOL
2928init_winsock (int load_now)
480b0c5b
GV
2929{
2930 WSADATA winsockData;
2931
f249a012
RS
2932 if (winsock_lib != NULL)
2933 return TRUE;
f1614061
RS
2934
2935 pfn_SetHandleInformation = NULL;
2936 pfn_SetHandleInformation
2937 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
2938 "SetHandleInformation");
2939
64570b36 2940 winsock_lib = LoadLibrary ("Ws2_32.dll");
480b0c5b
GV
2941
2942 if (winsock_lib != NULL)
2943 {
2944 /* dynamically link to socket functions */
2945
2946#define LOAD_PROC(fn) \
2947 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
2948 goto fail;
2949
2950 LOAD_PROC( WSAStartup );
2951 LOAD_PROC( WSASetLastError );
2952 LOAD_PROC( WSAGetLastError );
26fb7bc4 2953 LOAD_PROC( WSAEventSelect );
64570b36
KS
2954 LOAD_PROC( WSACreateEvent );
2955 LOAD_PROC( WSACloseEvent );
480b0c5b
GV
2956 LOAD_PROC( socket );
2957 LOAD_PROC( bind );
2958 LOAD_PROC( connect );
2959 LOAD_PROC( ioctlsocket );
2960 LOAD_PROC( recv );
2961 LOAD_PROC( send );
2962 LOAD_PROC( closesocket );
2963 LOAD_PROC( shutdown );
2964 LOAD_PROC( htons );
2965 LOAD_PROC( ntohs );
2966 LOAD_PROC( inet_addr );
2967 LOAD_PROC( gethostname );
2968 LOAD_PROC( gethostbyname );
2969 LOAD_PROC( getservbyname );
ecd270eb 2970 LOAD_PROC( getpeername );
480b0c5b 2971 LOAD_PROC( WSACleanup );
962955c5
JR
2972 LOAD_PROC( setsockopt );
2973 LOAD_PROC( listen );
2974 LOAD_PROC( getsockname );
2975 LOAD_PROC( accept );
2976 LOAD_PROC( recvfrom );
2977 LOAD_PROC( sendto );
f249a012
RS
2978#undef LOAD_PROC
2979
480b0c5b
GV
2980 /* specify version 1.1 of winsock */
2981 if (pfn_WSAStartup (0x101, &winsockData) == 0)
2982 {
f249a012
RS
2983 if (winsockData.wVersion != 0x101)
2984 goto fail;
2985
2986 if (!load_now)
2987 {
2988 /* Report that winsock exists and is usable, but leave
2989 socket functions disabled. I am assuming that calling
2990 WSAStartup does not require any network interaction,
2991 and in particular does not cause or require a dial-up
2992 connection to be established. */
2993
2994 pfn_WSACleanup ();
2995 FreeLibrary (winsock_lib);
2996 winsock_lib = NULL;
2997 }
2998 winsock_inuse = 0;
2999 return TRUE;
480b0c5b
GV
3000 }
3001
3002 fail:
3003 FreeLibrary (winsock_lib);
f249a012 3004 winsock_lib = NULL;
480b0c5b 3005 }
f249a012
RS
3006
3007 return FALSE;
480b0c5b
GV
3008}
3009
3010
3011int h_errno = 0;
3012
3013/* function to set h_errno for compatability; map winsock error codes to
3014 normal system codes where they overlap (non-overlapping definitions
3015 are already in <sys/socket.h> */
9bfb11f9
KS
3016static void
3017set_errno ()
480b0c5b 3018{
f249a012 3019 if (winsock_lib == NULL)
480b0c5b
GV
3020 h_errno = EINVAL;
3021 else
3022 h_errno = pfn_WSAGetLastError ();
3023
3024 switch (h_errno)
3025 {
3026 case WSAEACCES: h_errno = EACCES; break;
3027 case WSAEBADF: h_errno = EBADF; break;
3028 case WSAEFAULT: h_errno = EFAULT; break;
3029 case WSAEINTR: h_errno = EINTR; break;
3030 case WSAEINVAL: h_errno = EINVAL; break;
3031 case WSAEMFILE: h_errno = EMFILE; break;
3032 case WSAENAMETOOLONG: h_errno = ENAMETOOLONG; break;
3033 case WSAENOTEMPTY: h_errno = ENOTEMPTY; break;
3034 }
3035 errno = h_errno;
3036}
3037
9bfb11f9
KS
3038static void
3039check_errno ()
480b0c5b 3040{
f249a012 3041 if (h_errno == 0 && winsock_lib != NULL)
480b0c5b
GV
3042 pfn_WSASetLastError (0);
3043}
3044
d8fcc1b9
AI
3045/* Extend strerror to handle the winsock-specific error codes. */
3046struct {
3047 int errnum;
3048 char * msg;
3049} _wsa_errlist[] = {
3050 WSAEINTR , "Interrupted function call",
3051 WSAEBADF , "Bad file descriptor",
3052 WSAEACCES , "Permission denied",
3053 WSAEFAULT , "Bad address",
3054 WSAEINVAL , "Invalid argument",
3055 WSAEMFILE , "Too many open files",
177c0ea7 3056
d8fcc1b9
AI
3057 WSAEWOULDBLOCK , "Resource temporarily unavailable",
3058 WSAEINPROGRESS , "Operation now in progress",
3059 WSAEALREADY , "Operation already in progress",
3060 WSAENOTSOCK , "Socket operation on non-socket",
3061 WSAEDESTADDRREQ , "Destination address required",
3062 WSAEMSGSIZE , "Message too long",
3063 WSAEPROTOTYPE , "Protocol wrong type for socket",
3064 WSAENOPROTOOPT , "Bad protocol option",
3065 WSAEPROTONOSUPPORT , "Protocol not supported",
3066 WSAESOCKTNOSUPPORT , "Socket type not supported",
3067 WSAEOPNOTSUPP , "Operation not supported",
3068 WSAEPFNOSUPPORT , "Protocol family not supported",
3069 WSAEAFNOSUPPORT , "Address family not supported by protocol family",
3070 WSAEADDRINUSE , "Address already in use",
3071 WSAEADDRNOTAVAIL , "Cannot assign requested address",
3072 WSAENETDOWN , "Network is down",
3073 WSAENETUNREACH , "Network is unreachable",
3074 WSAENETRESET , "Network dropped connection on reset",
3075 WSAECONNABORTED , "Software caused connection abort",
3076 WSAECONNRESET , "Connection reset by peer",
3077 WSAENOBUFS , "No buffer space available",
3078 WSAEISCONN , "Socket is already connected",
3079 WSAENOTCONN , "Socket is not connected",
3080 WSAESHUTDOWN , "Cannot send after socket shutdown",
3081 WSAETOOMANYREFS , "Too many references", /* not sure */
3082 WSAETIMEDOUT , "Connection timed out",
3083 WSAECONNREFUSED , "Connection refused",
3084 WSAELOOP , "Network loop", /* not sure */
3085 WSAENAMETOOLONG , "Name is too long",
3086 WSAEHOSTDOWN , "Host is down",
3087 WSAEHOSTUNREACH , "No route to host",
3088 WSAENOTEMPTY , "Buffer not empty", /* not sure */
3089 WSAEPROCLIM , "Too many processes",
3090 WSAEUSERS , "Too many users", /* not sure */
3091 WSAEDQUOT , "Double quote in host name", /* really not sure */
3092 WSAESTALE , "Data is stale", /* not sure */
3093 WSAEREMOTE , "Remote error", /* not sure */
177c0ea7 3094
d8fcc1b9
AI
3095 WSASYSNOTREADY , "Network subsystem is unavailable",
3096 WSAVERNOTSUPPORTED , "WINSOCK.DLL version out of range",
3097 WSANOTINITIALISED , "Winsock not initialized successfully",
3098 WSAEDISCON , "Graceful shutdown in progress",
3099#ifdef WSAENOMORE
3100 WSAENOMORE , "No more operations allowed", /* not sure */
3101 WSAECANCELLED , "Operation cancelled", /* not sure */
3102 WSAEINVALIDPROCTABLE , "Invalid procedure table from service provider",
3103 WSAEINVALIDPROVIDER , "Invalid service provider version number",
3104 WSAEPROVIDERFAILEDINIT , "Unable to initialize a service provider",
aa5ee2a3 3105 WSASYSCALLFAILURE , "System call failure",
d8fcc1b9
AI
3106 WSASERVICE_NOT_FOUND , "Service not found", /* not sure */
3107 WSATYPE_NOT_FOUND , "Class type not found",
3108 WSA_E_NO_MORE , "No more resources available", /* really not sure */
3109 WSA_E_CANCELLED , "Operation already cancelled", /* really not sure */
3110 WSAEREFUSED , "Operation refused", /* not sure */
3111#endif
177c0ea7 3112
d8fcc1b9
AI
3113 WSAHOST_NOT_FOUND , "Host not found",
3114 WSATRY_AGAIN , "Authoritative host not found during name lookup",
3115 WSANO_RECOVERY , "Non-recoverable error during name lookup",
3116 WSANO_DATA , "Valid name, no data record of requested type",
3117
3118 -1, NULL
3119};
3120
3121char *
3122sys_strerror(int error_no)
3123{
3124 int i;
3125 static char unknown_msg[40];
3126
a302c7ae
AI
3127 if (error_no >= 0 && error_no < sys_nerr)
3128 return sys_errlist[error_no];
d8fcc1b9
AI
3129
3130 for (i = 0; _wsa_errlist[i].errnum >= 0; i++)
3131 if (_wsa_errlist[i].errnum == error_no)
3132 return _wsa_errlist[i].msg;
3133
3134 sprintf(unknown_msg, "Unidentified error: %d", error_no);
3135 return unknown_msg;
3136}
3137
480b0c5b
GV
3138/* [andrewi 3-May-96] I've had conflicting results using both methods,
3139 but I believe the method of keeping the socket handle separate (and
3140 insuring it is not inheritable) is the correct one. */
3141
3142//#define SOCK_REPLACE_HANDLE
3143
3144#ifdef SOCK_REPLACE_HANDLE
3145#define SOCK_HANDLE(fd) ((SOCKET) _get_osfhandle (fd))
3146#else
3147#define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
3148#endif
3149
962955c5
JR
3150int socket_to_fd (SOCKET s);
3151
480b0c5b
GV
3152int
3153sys_socket(int af, int type, int protocol)
3154{
962955c5 3155 SOCKET s;
480b0c5b 3156
f249a012 3157 if (winsock_lib == NULL)
480b0c5b
GV
3158 {
3159 h_errno = ENETDOWN;
3160 return INVALID_SOCKET;
3161 }
3162
3163 check_errno ();
3164
3165 /* call the real socket function */
962955c5 3166 s = pfn_socket (af, type, protocol);
177c0ea7 3167
480b0c5b 3168 if (s != INVALID_SOCKET)
962955c5 3169 return socket_to_fd (s);
480b0c5b 3170
962955c5
JR
3171 set_errno ();
3172 return -1;
3173}
3174
3175/* Convert a SOCKET to a file descriptor. */
3176int
3177socket_to_fd (SOCKET s)
3178{
3179 int fd;
3180 child_process * cp;
3181
3182 /* Although under NT 3.5 _open_osfhandle will accept a socket
3183 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
3184 that does not work under NT 3.1. However, we can get the same
3185 effect by using a backdoor function to replace an existing
3186 descriptor handle with the one we want. */
3187
3188 /* allocate a file descriptor (with appropriate flags) */
3189 fd = _open ("NUL:", _O_RDWR);
3190 if (fd >= 0)
3191 {
480b0c5b 3192#ifdef SOCK_REPLACE_HANDLE
962955c5
JR
3193 /* now replace handle to NUL with our socket handle */
3194 CloseHandle ((HANDLE) _get_osfhandle (fd));
3195 _free_osfhnd (fd);
3196 _set_osfhnd (fd, s);
3197 /* setmode (fd, _O_BINARY); */
480b0c5b 3198#else
962955c5
JR
3199 /* Make a non-inheritable copy of the socket handle. Note
3200 that it is possible that sockets aren't actually kernel
3201 handles, which appears to be the case on Windows 9x when
3202 the MS Proxy winsock client is installed. */
3203 {
3204 /* Apparently there is a bug in NT 3.51 with some service
3205 packs, which prevents using DuplicateHandle to make a
3206 socket handle non-inheritable (causes WSACleanup to
3207 hang). The work-around is to use SetHandleInformation
3208 instead if it is available and implemented. */
3209 if (pfn_SetHandleInformation)
480b0c5b 3210 {
962955c5
JR
3211 pfn_SetHandleInformation ((HANDLE) s, HANDLE_FLAG_INHERIT, 0);
3212 }
3213 else
3214 {
3215 HANDLE parent = GetCurrentProcess ();
3216 HANDLE new_s = INVALID_HANDLE_VALUE;
3217
3218 if (DuplicateHandle (parent,
3219 (HANDLE) s,
3220 parent,
3221 &new_s,
3222 0,
3223 FALSE,
3224 DUPLICATE_SAME_ACCESS))
f1614061 3225 {
962955c5
JR
3226 /* It is possible that DuplicateHandle succeeds even
3227 though the socket wasn't really a kernel handle,
3228 because a real handle has the same value. So
3229 test whether the new handle really is a socket. */
3230 long nonblocking = 0;
3231 if (pfn_ioctlsocket ((SOCKET) new_s, FIONBIO, &nonblocking) == 0)
ca149beb 3232 {
962955c5
JR
3233 pfn_closesocket (s);
3234 s = (SOCKET) new_s;
3235 }
3236 else
3237 {
3238 CloseHandle (new_s);
3239 }
177c0ea7 3240 }
480b0c5b 3241 }
962955c5
JR
3242 }
3243 fd_info[fd].hnd = (HANDLE) s;
480b0c5b
GV
3244#endif
3245
962955c5
JR
3246 /* set our own internal flags */
3247 fd_info[fd].flags = FILE_SOCKET | FILE_BINARY | FILE_READ | FILE_WRITE;
480b0c5b 3248
962955c5
JR
3249 cp = new_child ();
3250 if (cp)
3251 {
3252 cp->fd = fd;
3253 cp->status = STATUS_READ_ACKNOWLEDGED;
480b0c5b 3254
962955c5
JR
3255 /* attach child_process to fd_info */
3256 if (fd_info[ fd ].cp != NULL)
3257 {
3258 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd));
3259 abort ();
480b0c5b
GV
3260 }
3261
962955c5
JR
3262 fd_info[ fd ].cp = cp;
3263
3264 /* success! */
3265 winsock_inuse++; /* count open sockets */
3266 return fd;
480b0c5b 3267 }
480b0c5b 3268
962955c5
JR
3269 /* clean up */
3270 _close (fd);
3271 }
3272 pfn_closesocket (s);
3273 h_errno = EMFILE;
480b0c5b
GV
3274 return -1;
3275}
3276
3277
3278int
3279sys_bind (int s, const struct sockaddr * addr, int namelen)
3280{
f249a012 3281 if (winsock_lib == NULL)
480b0c5b
GV
3282 {
3283 h_errno = ENOTSOCK;
3284 return SOCKET_ERROR;
3285 }
3286
3287 check_errno ();
3288 if (fd_info[s].flags & FILE_SOCKET)
3289 {
3290 int rc = pfn_bind (SOCK_HANDLE (s), addr, namelen);
3291 if (rc == SOCKET_ERROR)
3292 set_errno ();
3293 return rc;
3294 }
3295 h_errno = ENOTSOCK;
3296 return SOCKET_ERROR;
3297}
3298
3299
3300int
3301sys_connect (int s, const struct sockaddr * name, int namelen)
3302{
f249a012 3303 if (winsock_lib == NULL)
480b0c5b
GV
3304 {
3305 h_errno = ENOTSOCK;
3306 return SOCKET_ERROR;
3307 }
3308
3309 check_errno ();
3310 if (fd_info[s].flags & FILE_SOCKET)
3311 {
3312 int rc = pfn_connect (SOCK_HANDLE (s), name, namelen);
3313 if (rc == SOCKET_ERROR)
3314 set_errno ();
3315 return rc;
3316 }
3317 h_errno = ENOTSOCK;
3318 return SOCKET_ERROR;
3319}
3320
3321u_short
3322sys_htons (u_short hostshort)
3323{
f249a012 3324 return (winsock_lib != NULL) ?
480b0c5b
GV
3325 pfn_htons (hostshort) : hostshort;
3326}
3327
3328u_short
3329sys_ntohs (u_short netshort)
3330{
f249a012 3331 return (winsock_lib != NULL) ?
480b0c5b
GV
3332 pfn_ntohs (netshort) : netshort;
3333}
3334
3335unsigned long
3336sys_inet_addr (const char * cp)
3337{
f249a012 3338 return (winsock_lib != NULL) ?
480b0c5b
GV
3339 pfn_inet_addr (cp) : INADDR_NONE;
3340}
3341
3342int
3343sys_gethostname (char * name, int namelen)
3344{
f249a012 3345 if (winsock_lib != NULL)
480b0c5b
GV
3346 return pfn_gethostname (name, namelen);
3347
3348 if (namelen > MAX_COMPUTERNAME_LENGTH)
a302c7ae 3349 return !GetComputerName (name, (DWORD *)&namelen);
480b0c5b
GV
3350
3351 h_errno = EFAULT;
3352 return SOCKET_ERROR;
3353}
3354
3355struct hostent *
3356sys_gethostbyname(const char * name)
3357{
3358 struct hostent * host;
3359
f249a012 3360 if (winsock_lib == NULL)
480b0c5b
GV
3361 {
3362 h_errno = ENETDOWN;
3363 return NULL;
3364 }
3365
3366 check_errno ();
3367 host = pfn_gethostbyname (name);
3368 if (!host)
3369 set_errno ();
3370 return host;
3371}
3372
3373struct servent *
3374sys_getservbyname(const char * name, const char * proto)
3375{
3376 struct servent * serv;
3377
f249a012 3378 if (winsock_lib == NULL)
480b0c5b
GV
3379 {
3380 h_errno = ENETDOWN;
3381 return NULL;
3382 }
3383
3384 check_errno ();
3385 serv = pfn_getservbyname (name, proto);
3386 if (!serv)
3387 set_errno ();
3388 return serv;
3389}
3390
ecd270eb
JR
3391int
3392sys_getpeername (int s, struct sockaddr *addr, int * namelen)
3393{
3394 if (winsock_lib == NULL)
3395 {
3396 h_errno = ENETDOWN;
3397 return SOCKET_ERROR;
3398 }
3399
3400 check_errno ();
3401 if (fd_info[s].flags & FILE_SOCKET)
3402 {
3403 int rc = pfn_getpeername (SOCK_HANDLE (s), addr, namelen);
3404 if (rc == SOCKET_ERROR)
3405 set_errno ();
3406 return rc;
3407 }
3408 h_errno = ENOTSOCK;
3409 return SOCKET_ERROR;
3410}
3411
3412
380961a6
GV
3413int
3414sys_shutdown (int s, int how)
3415{
380961a6
GV
3416 if (winsock_lib == NULL)
3417 {
3418 h_errno = ENETDOWN;
3419 return SOCKET_ERROR;
3420 }
3421
3422 check_errno ();
3423 if (fd_info[s].flags & FILE_SOCKET)
3424 {
3425 int rc = pfn_shutdown (SOCK_HANDLE (s), how);
962955c5
JR
3426 if (rc == SOCKET_ERROR)
3427 set_errno ();
3428 return rc;
3429 }
3430 h_errno = ENOTSOCK;
3431 return SOCKET_ERROR;
3432}
3433
3434int
a5a389bb 3435sys_setsockopt (int s, int level, int optname, const void * optval, int optlen)
962955c5
JR
3436{
3437 if (winsock_lib == NULL)
3438 {
3439 h_errno = ENETDOWN;
3440 return SOCKET_ERROR;
3441 }
3442
3443 check_errno ();
3444 if (fd_info[s].flags & FILE_SOCKET)
3445 {
3446 int rc = pfn_setsockopt (SOCK_HANDLE (s), level, optname,
a5a389bb 3447 (const char *)optval, optlen);
962955c5
JR
3448 if (rc == SOCKET_ERROR)
3449 set_errno ();
3450 return rc;
3451 }
3452 h_errno = ENOTSOCK;
177c0ea7 3453 return SOCKET_ERROR;
962955c5
JR
3454}
3455
3456int
3457sys_listen (int s, int backlog)
3458{
3459 if (winsock_lib == NULL)
3460 {
3461 h_errno = ENETDOWN;
3462 return SOCKET_ERROR;
3463 }
3464
3465 check_errno ();
3466 if (fd_info[s].flags & FILE_SOCKET)
3467 {
3468 int rc = pfn_listen (SOCK_HANDLE (s), backlog);
3469 if (rc == SOCKET_ERROR)
3470 set_errno ();
26fb7bc4 3471 else
64570b36 3472 fd_info[s].flags |= FILE_LISTEN;
962955c5
JR
3473 return rc;
3474 }
3475 h_errno = ENOTSOCK;
177c0ea7 3476 return SOCKET_ERROR;
962955c5
JR
3477}
3478
3479int
3480sys_getsockname (int s, struct sockaddr * name, int * namelen)
3481{
3482 if (winsock_lib == NULL)
3483 {
3484 h_errno = ENETDOWN;
3485 return SOCKET_ERROR;
3486 }
3487
3488 check_errno ();
3489 if (fd_info[s].flags & FILE_SOCKET)
3490 {
3491 int rc = pfn_getsockname (SOCK_HANDLE (s), name, namelen);
3492 if (rc == SOCKET_ERROR)
3493 set_errno ();
3494 return rc;
3495 }
3496 h_errno = ENOTSOCK;
177c0ea7 3497 return SOCKET_ERROR;
962955c5
JR
3498}
3499
3500int
3501sys_accept (int s, struct sockaddr * addr, int * addrlen)
3502{
3503 if (winsock_lib == NULL)
3504 {
3505 h_errno = ENETDOWN;
3506 return -1;
3507 }
3508
3509 check_errno ();
26fb7bc4 3510 if (fd_info[s].flags & FILE_LISTEN)
962955c5 3511 {
a0ad1860 3512 SOCKET t = pfn_accept (SOCK_HANDLE (s), addr, addrlen);
64570b36
KS
3513 int fd = -1;
3514 if (t == INVALID_SOCKET)
3515 set_errno ();
3516 else
3517 fd = socket_to_fd (t);
962955c5 3518
64570b36
KS
3519 fd_info[s].cp->status = STATUS_READ_ACKNOWLEDGED;
3520 ResetEvent (fd_info[s].cp->char_avail);
3521 return fd;
962955c5
JR
3522 }
3523 h_errno = ENOTSOCK;
3524 return -1;
3525}
3526
3527int
3528sys_recvfrom (int s, char * buf, int len, int flags,
3529 struct sockaddr * from, int * fromlen)
3530{
3531 if (winsock_lib == NULL)
3532 {
3533 h_errno = ENETDOWN;
3534 return SOCKET_ERROR;
3535 }
3536
3537 check_errno ();
3538 if (fd_info[s].flags & FILE_SOCKET)
3539 {
3540 int rc = pfn_recvfrom (SOCK_HANDLE (s), buf, len, flags, from, fromlen);
3541 if (rc == SOCKET_ERROR)
3542 set_errno ();
3543 return rc;
3544 }
3545 h_errno = ENOTSOCK;
3546 return SOCKET_ERROR;
3547}
3548
3549int
3550sys_sendto (int s, const char * buf, int len, int flags,
3551 const struct sockaddr * to, int tolen)
3552{
3553 if (winsock_lib == NULL)
3554 {
3555 h_errno = ENETDOWN;
3556 return SOCKET_ERROR;
3557 }
3558
3559 check_errno ();
3560 if (fd_info[s].flags & FILE_SOCKET)
3561 {
3562 int rc = pfn_sendto (SOCK_HANDLE (s), buf, len, flags, to, tolen);
380961a6
GV
3563 if (rc == SOCKET_ERROR)
3564 set_errno ();
3565 return rc;
3566 }
3567 h_errno = ENOTSOCK;
3568 return SOCKET_ERROR;
3569}
3570
ecd270eb
JR
3571/* Windows does not have an fcntl function. Provide an implementation
3572 solely for making sockets non-blocking. */
3573int
3574fcntl (int s, int cmd, int options)
3575{
3576 if (winsock_lib == NULL)
3577 {
3578 h_errno = ENETDOWN;
3579 return -1;
3580 }
3581
3582 check_errno ();
3583 if (fd_info[s].flags & FILE_SOCKET)
3584 {
3585 if (cmd == F_SETFL && options == O_NDELAY)
3586 {
3587 unsigned long nblock = 1;
3588 int rc = pfn_ioctlsocket (SOCK_HANDLE (s), FIONBIO, &nblock);
3589 if (rc == SOCKET_ERROR)
3590 set_errno();
3591 /* Keep track of the fact that we set this to non-blocking. */
3592 fd_info[s].flags |= FILE_NDELAY;
3593 return rc;
3594 }
3595 else
3596 {
3597 h_errno = EINVAL;
3598 return SOCKET_ERROR;
3599 }
3600 }
3601 h_errno = ENOTSOCK;
3602 return SOCKET_ERROR;
3603}
3604
480b0c5b
GV
3605#endif /* HAVE_SOCKETS */
3606
3607
3608/* Shadow main io functions: we need to handle pipes and sockets more
3609 intelligently, and implement non-blocking mode as well. */
3610
3611int
3612sys_close (int fd)
3613{
3614 int rc;
3615
7559f399 3616 if (fd < 0)
480b0c5b
GV
3617 {
3618 errno = EBADF;
3619 return -1;
3620 }
3621
7559f399 3622 if (fd < MAXDESC && fd_info[fd].cp)
480b0c5b
GV
3623 {
3624 child_process * cp = fd_info[fd].cp;
3625
3626 fd_info[fd].cp = NULL;
3627
3628 if (CHILD_ACTIVE (cp))
3629 {
3630 /* if last descriptor to active child_process then cleanup */
3631 int i;
3632 for (i = 0; i < MAXDESC; i++)
3633 {
3634 if (i == fd)
3635 continue;
3636 if (fd_info[i].cp == cp)
3637 break;
3638 }
3639 if (i == MAXDESC)
3640 {
f249a012 3641#ifdef HAVE_SOCKETS
480b0c5b
GV
3642 if (fd_info[fd].flags & FILE_SOCKET)
3643 {
f249a012
RS
3644#ifndef SOCK_REPLACE_HANDLE
3645 if (winsock_lib == NULL) abort ();
480b0c5b
GV
3646
3647 pfn_shutdown (SOCK_HANDLE (fd), 2);
3648 rc = pfn_closesocket (SOCK_HANDLE (fd));
f249a012
RS
3649#endif
3650 winsock_inuse--; /* count open sockets */
480b0c5b
GV
3651 }
3652#endif
3653 delete_child (cp);
3654 }
3655 }
3656 }
3657
3658 /* Note that sockets do not need special treatment here (at least on
e9e23e23 3659 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
480b0c5b
GV
3660 closesocket is equivalent to CloseHandle, which is to be expected
3661 because socket handles are fully fledged kernel handles. */
3662 rc = _close (fd);
3663
7559f399 3664 if (rc == 0 && fd < MAXDESC)
480b0c5b
GV
3665 fd_info[fd].flags = 0;
3666
3667 return rc;
3668}
3669
3670int
3671sys_dup (int fd)
3672{
3673 int new_fd;
3674
3675 new_fd = _dup (fd);
7559f399 3676 if (new_fd >= 0 && new_fd < MAXDESC)
480b0c5b
GV
3677 {
3678 /* duplicate our internal info as well */
3679 fd_info[new_fd] = fd_info[fd];
3680 }
3681 return new_fd;
3682}
3683
3684
3685int
3686sys_dup2 (int src, int dst)
3687{
3688 int rc;
3689
3690 if (dst < 0 || dst >= MAXDESC)
3691 {
3692 errno = EBADF;
3693 return -1;
3694 }
3695
3696 /* make sure we close the destination first if it's a pipe or socket */
3697 if (src != dst && fd_info[dst].flags != 0)
3698 sys_close (dst);
177c0ea7 3699
480b0c5b
GV
3700 rc = _dup2 (src, dst);
3701 if (rc == 0)
3702 {
3703 /* duplicate our internal info as well */
3704 fd_info[dst] = fd_info[src];
3705 }
3706 return rc;
3707}
3708
480b0c5b
GV
3709/* Unix pipe() has only one arg */
3710int
3711sys_pipe (int * phandles)
3712{
3713 int rc;
3714 unsigned flags;
480b0c5b 3715
76b3903d
GV
3716 /* make pipe handles non-inheritable; when we spawn a child, we
3717 replace the relevant handle with an inheritable one. Also put
3718 pipes into binary mode; we will do text mode translation ourselves
3719 if required. */
3720 rc = _pipe (phandles, 0, _O_NOINHERIT | _O_BINARY);
480b0c5b
GV
3721
3722 if (rc == 0)
3723 {
cb72110d
JR
3724 /* Protect against overflow, since Windows can open more handles than
3725 our fd_info array has room for. */
3726 if (phandles[0] >= MAXDESC || phandles[1] >= MAXDESC)
3727 {
3728 _close (phandles[0]);
3729 _close (phandles[1]);
3730 rc = -1;
3731 }
3732 else
3733 {
3734 flags = FILE_PIPE | FILE_READ | FILE_BINARY;
3735 fd_info[phandles[0]].flags = flags;
480b0c5b 3736
cb72110d
JR
3737 flags = FILE_PIPE | FILE_WRITE | FILE_BINARY;
3738 fd_info[phandles[1]].flags = flags;
3739 }
480b0c5b
GV
3740 }
3741
3742 return rc;
3743}
3744
f7554349 3745/* From ntproc.c */
78806724 3746extern int w32_pipe_read_delay;
f7554349 3747
480b0c5b
GV
3748/* Function to do blocking read of one byte, needed to implement
3749 select. It is only allowed on sockets and pipes. */
3750int
3751_sys_read_ahead (int fd)
3752{
3753 child_process * cp;
3754 int rc;
3755
3756 if (fd < 0 || fd >= MAXDESC)
3757 return STATUS_READ_ERROR;
3758
3759 cp = fd_info[fd].cp;
3760
3761 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
3762 return STATUS_READ_ERROR;
3763
3764 if ((fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET)) == 0
3765 || (fd_info[fd].flags & FILE_READ) == 0)
3766 {
3767 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe or socket!\n", fd));
3768 abort ();
3769 }
177c0ea7 3770
480b0c5b 3771 cp->status = STATUS_READ_IN_PROGRESS;
177c0ea7 3772
480b0c5b 3773 if (fd_info[fd].flags & FILE_PIPE)
f7554349 3774 {
f7554349
KH
3775 rc = _read (fd, &cp->chr, sizeof (char));
3776
3777 /* Give subprocess time to buffer some more output for us before
e9e23e23 3778 reporting that input is available; we need this because Windows 95
f7554349
KH
3779 connects DOS programs to pipes by making the pipe appear to be
3780 the normal console stdout - as a result most DOS programs will
3781 write to stdout without buffering, ie. one character at a
fbd6baed 3782 time. Even some W32 programs do this - "dir" in a command
f7554349
KH
3783 shell on NT is very slow if we don't do this. */
3784 if (rc > 0)
3785 {
78806724 3786 int wait = w32_pipe_read_delay;
f7554349
KH
3787
3788 if (wait > 0)
3789 Sleep (wait);
3790 else if (wait < 0)
3791 while (++wait <= 0)
3792 /* Yield remainder of our time slice, effectively giving a
3793 temporary priority boost to the child process. */
3794 Sleep (0);
3795 }
3796 }
480b0c5b
GV
3797#ifdef HAVE_SOCKETS
3798 else if (fd_info[fd].flags & FILE_SOCKET)
ecd270eb
JR
3799 {
3800 unsigned long nblock = 0;
3801 /* We always want this to block, so temporarily disable NDELAY. */
3802 if (fd_info[fd].flags & FILE_NDELAY)
3803 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
3804
3805 rc = pfn_recv (SOCK_HANDLE (fd), &cp->chr, sizeof (char), 0);
3806
3807 if (fd_info[fd].flags & FILE_NDELAY)
3808 {
3809 nblock = 1;
3810 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
3811 }
3812 }
480b0c5b 3813#endif
177c0ea7 3814
480b0c5b
GV
3815 if (rc == sizeof (char))
3816 cp->status = STATUS_READ_SUCCEEDED;
3817 else
3818 cp->status = STATUS_READ_FAILED;
3819
3820 return cp->status;
3821}
3822
9bfb11f9
KS
3823int
3824_sys_wait_accept (int fd)
64570b36
KS
3825{
3826 HANDLE hEv;
3827 child_process * cp;
3828 int rc;
3829
3830 if (fd < 0 || fd >= MAXDESC)
3831 return STATUS_READ_ERROR;
3832
3833 cp = fd_info[fd].cp;
3834
3835 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
3836 return STATUS_READ_ERROR;
3837
3838 cp->status = STATUS_READ_FAILED;
3839
3840 hEv = pfn_WSACreateEvent ();
3841 rc = pfn_WSAEventSelect (SOCK_HANDLE (fd), hEv, FD_ACCEPT);
3842 if (rc != SOCKET_ERROR)
3843 {
3844 rc = WaitForSingleObject (hEv, INFINITE);
3845 pfn_WSAEventSelect (SOCK_HANDLE (fd), NULL, 0);
64570b36
KS
3846 if (rc == WAIT_OBJECT_0)
3847 cp->status = STATUS_READ_SUCCEEDED;
3848 }
7046f191 3849 pfn_WSACloseEvent (hEv);
64570b36
KS
3850
3851 return cp->status;
3852}
3853
480b0c5b
GV
3854int
3855sys_read (int fd, char * buffer, unsigned int count)
3856{
3857 int nchars;
480b0c5b
GV
3858 int to_read;
3859 DWORD waiting;
76b3903d 3860 char * orig_buffer = buffer;
480b0c5b 3861
7559f399 3862 if (fd < 0)
480b0c5b
GV
3863 {
3864 errno = EBADF;
3865 return -1;
3866 }
3867
7559f399 3868 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET))
480b0c5b
GV
3869 {
3870 child_process *cp = fd_info[fd].cp;
3871
3872 if ((fd_info[fd].flags & FILE_READ) == 0)
3873 {
3874 errno = EBADF;
3875 return -1;
3876 }
3877
76b3903d
GV
3878 nchars = 0;
3879
3880 /* re-read CR carried over from last read */
3881 if (fd_info[fd].flags & FILE_LAST_CR)
3882 {
3883 if (fd_info[fd].flags & FILE_BINARY) abort ();
3884 *buffer++ = 0x0d;
3885 count--;
3886 nchars++;
f52eb3ef 3887 fd_info[fd].flags &= ~FILE_LAST_CR;
76b3903d
GV
3888 }
3889
480b0c5b
GV
3890 /* presence of a child_process structure means we are operating in
3891 non-blocking mode - otherwise we just call _read directly.
3892 Note that the child_process structure might be missing because
3893 reap_subprocess has been called; in this case the pipe is
3894 already broken, so calling _read on it is okay. */
3895 if (cp)
3896 {
3897 int current_status = cp->status;
3898
3899 switch (current_status)
3900 {
3901 case STATUS_READ_FAILED:
3902 case STATUS_READ_ERROR:
f52eb3ef
GV
3903 /* report normal EOF if nothing in buffer */
3904 if (nchars <= 0)
3905 fd_info[fd].flags |= FILE_AT_EOF;
3906 return nchars;
480b0c5b
GV
3907
3908 case STATUS_READ_READY:
3909 case STATUS_READ_IN_PROGRESS:
3910 DebPrint (("sys_read called when read is in progress\n"));
3911 errno = EWOULDBLOCK;
3912 return -1;
3913
3914 case STATUS_READ_SUCCEEDED:
3915 /* consume read-ahead char */
3916 *buffer++ = cp->chr;
3917 count--;
76b3903d 3918 nchars++;
480b0c5b
GV
3919 cp->status = STATUS_READ_ACKNOWLEDGED;
3920 ResetEvent (cp->char_avail);
3921
3922 case STATUS_READ_ACKNOWLEDGED:
3923 break;
3924
3925 default:
3926 DebPrint (("sys_read: bad status %d\n", current_status));
3927 errno = EBADF;
3928 return -1;
3929 }
3930
3931 if (fd_info[fd].flags & FILE_PIPE)
3932 {
3933 PeekNamedPipe ((HANDLE) _get_osfhandle (fd), NULL, 0, NULL, &waiting, NULL);
3934 to_read = min (waiting, (DWORD) count);
f52eb3ef
GV
3935
3936 if (to_read > 0)
3937 nchars += _read (fd, buffer, to_read);
480b0c5b
GV
3938 }
3939#ifdef HAVE_SOCKETS
3940 else /* FILE_SOCKET */
3941 {
f249a012 3942 if (winsock_lib == NULL) abort ();
480b0c5b
GV
3943
3944 /* do the equivalent of a non-blocking read */
3945 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONREAD, &waiting);
76b3903d 3946 if (waiting == 0 && nchars == 0)
480b0c5b
GV
3947 {
3948 h_errno = errno = EWOULDBLOCK;
3949 return -1;
3950 }
3951
480b0c5b
GV
3952 if (waiting)
3953 {
3954 /* always use binary mode for sockets */
76b3903d
GV
3955 int res = pfn_recv (SOCK_HANDLE (fd), buffer, count, 0);
3956 if (res == SOCKET_ERROR)
480b0c5b
GV
3957 {
3958 DebPrint(("sys_read.recv failed with error %d on socket %ld\n",
3959 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
76b3903d
GV
3960 set_errno ();
3961 return -1;
480b0c5b 3962 }
76b3903d 3963 nchars += res;
480b0c5b
GV
3964 }
3965 }
3966#endif
3967 }
3968 else
f52eb3ef
GV
3969 {
3970 int nread = _read (fd, buffer, count);
3971 if (nread >= 0)
3972 nchars += nread;
3973 else if (nchars == 0)
3974 nchars = nread;
3975 }
76b3903d 3976
f52eb3ef
GV
3977 if (nchars <= 0)
3978 fd_info[fd].flags |= FILE_AT_EOF;
76b3903d 3979 /* Perform text mode translation if required. */
f52eb3ef 3980 else if ((fd_info[fd].flags & FILE_BINARY) == 0)
76b3903d
GV
3981 {
3982 nchars = crlf_to_lf (nchars, orig_buffer);
3983 /* If buffer contains only CR, return that. To be absolutely
3984 sure we should attempt to read the next char, but in
3985 practice a CR to be followed by LF would not appear by
3986 itself in the buffer. */
3987 if (nchars > 1 && orig_buffer[nchars - 1] == 0x0d)
3988 {
3989 fd_info[fd].flags |= FILE_LAST_CR;
3990 nchars--;
3991 }
76b3903d 3992 }
480b0c5b
GV
3993 }
3994 else
3995 nchars = _read (fd, buffer, count);
3996
76b3903d 3997 return nchars;
480b0c5b
GV
3998}
3999
4000/* For now, don't bother with a non-blocking mode */
4001int
4002sys_write (int fd, const void * buffer, unsigned int count)
4003{
4004 int nchars;
4005
7559f399 4006 if (fd < 0)
480b0c5b
GV
4007 {
4008 errno = EBADF;
4009 return -1;
4010 }
4011
7559f399 4012 if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET))
76b3903d
GV
4013 {
4014 if ((fd_info[fd].flags & FILE_WRITE) == 0)
4015 {
4016 errno = EBADF;
4017 return -1;
4018 }
4019
4020 /* Perform text mode translation if required. */
4021 if ((fd_info[fd].flags & FILE_BINARY) == 0)
4022 {
4023 char * tmpbuf = alloca (count * 2);
4024 unsigned char * src = (void *)buffer;
4025 unsigned char * dst = tmpbuf;
4026 int nbytes = count;
4027
4028 while (1)
4029 {
4030 unsigned char *next;
4031 /* copy next line or remaining bytes */
4032 next = _memccpy (dst, src, '\n', nbytes);
4033 if (next)
4034 {
4035 /* copied one line ending with '\n' */
4036 int copied = next - dst;
4037 nbytes -= copied;
4038 src += copied;
4039 /* insert '\r' before '\n' */
4040 next[-1] = '\r';
4041 next[0] = '\n';
4042 dst = next + 1;
4043 count++;
177c0ea7 4044 }
76b3903d
GV
4045 else
4046 /* copied remaining partial line -> now finished */
4047 break;
4048 }
4049 buffer = tmpbuf;
4050 }
4051 }
4052
480b0c5b 4053#ifdef HAVE_SOCKETS
7559f399 4054 if (fd < MAXDESC && fd_info[fd].flags & FILE_SOCKET)
480b0c5b 4055 {
30a32e0e 4056 unsigned long nblock = 0;
f249a012 4057 if (winsock_lib == NULL) abort ();
30a32e0e
JR
4058
4059 /* TODO: implement select() properly so non-blocking I/O works. */
4060 /* For now, make sure the write blocks. */
4061 if (fd_info[fd].flags & FILE_NDELAY)
4062 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
4063
480b0c5b 4064 nchars = pfn_send (SOCK_HANDLE (fd), buffer, count, 0);
30a32e0e
JR
4065
4066 /* Set the socket back to non-blocking if it was before,
4067 for other operations that support it. */
4068 if (fd_info[fd].flags & FILE_NDELAY)
4069 {
4070 nblock = 1;
4071 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONBIO, &nblock);
4072 }
4073
480b0c5b
GV
4074 if (nchars == SOCKET_ERROR)
4075 {
670773af 4076 DebPrint(("sys_write.send failed with error %d on socket %ld\n",
480b0c5b
GV
4077 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
4078 set_errno ();
4079 }
4080 }
4081 else
4082#endif
4083 nchars = _write (fd, buffer, count);
4084
4085 return nchars;
4086}
4087
f52eb3ef
GV
4088static void
4089check_windows_init_file ()
4090{
4091 extern int noninteractive, inhibit_window_system;
4092
4093 /* A common indication that Emacs is not installed properly is when
4094 it cannot find the Windows installation file. If this file does
4095 not exist in the expected place, tell the user. */
4096
177c0ea7 4097 if (!noninteractive && !inhibit_window_system)
d54abccd
GV
4098 {
4099 extern Lisp_Object Vwindow_system, Vload_path, Qfile_exists_p;
a0b9c838 4100 Lisp_Object objs[2];
96ef7d42 4101 Lisp_Object full_load_path;
d54abccd
GV
4102 Lisp_Object init_file;
4103 int fd;
f52eb3ef 4104
a0b9c838
GV
4105 objs[0] = Vload_path;
4106 objs[1] = decode_env_path (0, (getenv ("EMACSLOADPATH")));
4107 full_load_path = Fappend (2, objs);
d54abccd 4108 init_file = build_string ("term/w32-win");
c50a2aa6 4109 fd = openp (full_load_path, init_file, Fget_load_suffixes (), NULL, Qnil);
177c0ea7 4110 if (fd < 0)
d54abccd 4111 {
96ef7d42 4112 Lisp_Object load_path_print = Fprin1_to_string (full_load_path, Qnil);
d5db4077
KR
4113 char *init_file_name = SDATA (init_file);
4114 char *load_path = SDATA (load_path_print);
acc23b87
KS
4115 char *buffer = alloca (1024
4116 + strlen (init_file_name)
4117 + strlen (load_path));
d54abccd 4118
177c0ea7 4119 sprintf (buffer,
d54abccd
GV
4120 "The Emacs Windows initialization file \"%s.el\" "
4121 "could not be found in your Emacs installation. "
4122 "Emacs checked the following directories for this file:\n"
4123 "\n%s\n\n"
4124 "When Emacs cannot find this file, it usually means that it "
4125 "was not installed properly, or its distribution file was "
4126 "not unpacked properly.\nSee the README.W32 file in the "
4127 "top-level Emacs directory for more information.",
4128 init_file_name, load_path);
4129 MessageBox (NULL,
4130 buffer,
4131 "Emacs Abort Dialog",
4132 MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
f52eb3ef
GV
4133 /* Use the low-level Emacs abort. */
4134#undef abort
d54abccd
GV
4135 abort ();
4136 }
4137 else
4138 {
a302c7ae 4139 _close (fd);
d54abccd 4140 }
f52eb3ef 4141 }
f52eb3ef 4142}
480b0c5b
GV
4143
4144void
4145term_ntproc ()
4146{
4147#ifdef HAVE_SOCKETS
4148 /* shutdown the socket interface if necessary */
4149 term_winsock ();
4150#endif
52c7f9ee
JR
4151
4152 term_w32select ();
480b0c5b
GV
4153}
4154
4155void
4156init_ntproc ()
4157{
4158#ifdef HAVE_SOCKETS
f249a012
RS
4159 /* Initialise the socket interface now if available and requested by
4160 the user by defining PRELOAD_WINSOCK; otherwise loading will be
fbd6baed 4161 delayed until open-network-stream is called (w32-has-winsock can
f249a012
RS
4162 also be used to dynamically load or reload winsock).
4163
4164 Conveniently, init_environment is called before us, so
4165 PRELOAD_WINSOCK can be set in the registry. */
4166
4167 /* Always initialize this correctly. */
4168 winsock_lib = NULL;
4169
4170 if (getenv ("PRELOAD_WINSOCK") != NULL)
4171 init_winsock (TRUE);
480b0c5b
GV
4172#endif
4173
4174 /* Initial preparation for subprocess support: replace our standard
4175 handles with non-inheritable versions. */
4176 {
4177 HANDLE parent;
4178 HANDLE stdin_save = INVALID_HANDLE_VALUE;
4179 HANDLE stdout_save = INVALID_HANDLE_VALUE;
4180 HANDLE stderr_save = INVALID_HANDLE_VALUE;
4181
4182 parent = GetCurrentProcess ();
4183
4184 /* ignore errors when duplicating and closing; typically the
4185 handles will be invalid when running as a gui program. */
177c0ea7
JB
4186 DuplicateHandle (parent,
4187 GetStdHandle (STD_INPUT_HANDLE),
480b0c5b 4188 parent,
177c0ea7
JB
4189 &stdin_save,
4190 0,
4191 FALSE,
480b0c5b 4192 DUPLICATE_SAME_ACCESS);
177c0ea7 4193
480b0c5b
GV
4194 DuplicateHandle (parent,
4195 GetStdHandle (STD_OUTPUT_HANDLE),
4196 parent,
4197 &stdout_save,
4198 0,
4199 FALSE,
4200 DUPLICATE_SAME_ACCESS);
177c0ea7 4201
480b0c5b
GV
4202 DuplicateHandle (parent,
4203 GetStdHandle (STD_ERROR_HANDLE),
4204 parent,
4205 &stderr_save,
4206 0,
4207 FALSE,
4208 DUPLICATE_SAME_ACCESS);
177c0ea7 4209
480b0c5b
GV
4210 fclose (stdin);
4211 fclose (stdout);
4212 fclose (stderr);
4213
4214 if (stdin_save != INVALID_HANDLE_VALUE)
4215 _open_osfhandle ((long) stdin_save, O_TEXT);
4216 else
76b3903d
GV
4217 _open ("nul", O_TEXT | O_NOINHERIT | O_RDONLY);
4218 _fdopen (0, "r");
480b0c5b
GV
4219
4220 if (stdout_save != INVALID_HANDLE_VALUE)
4221 _open_osfhandle ((long) stdout_save, O_TEXT);
4222 else
76b3903d
GV
4223 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
4224 _fdopen (1, "w");
480b0c5b
GV
4225
4226 if (stderr_save != INVALID_HANDLE_VALUE)
4227 _open_osfhandle ((long) stderr_save, O_TEXT);
4228 else
76b3903d
GV
4229 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
4230 _fdopen (2, "w");
480b0c5b
GV
4231 }
4232
4233 /* unfortunately, atexit depends on implementation of malloc */
4234 /* atexit (term_ntproc); */
4235 signal (SIGABRT, term_ntproc);
76b3903d
GV
4236
4237 /* determine which drives are fixed, for GetCachedVolumeInformation */
4238 {
4239 /* GetDriveType must have trailing backslash. */
4240 char drive[] = "A:\\";
4241
4242 /* Loop over all possible drive letters */
4243 while (*drive <= 'Z')
4244 {
4245 /* Record if this drive letter refers to a fixed drive. */
177c0ea7 4246 fixed_drives[DRIVE_INDEX (*drive)] =
76b3903d
GV
4247 (GetDriveType (drive) == DRIVE_FIXED);
4248
4249 (*drive)++;
4250 }
a302c7ae
AI
4251
4252 /* Reset the volume info cache. */
4253 volume_cache = NULL;
76b3903d 4254 }
177c0ea7 4255
d54abccd
GV
4256 /* Check to see if Emacs has been installed correctly. */
4257 check_windows_init_file ();
480b0c5b
GV
4258}
4259
a8c3a596
JR
4260/*
4261 shutdown_handler ensures that buffers' autosave files are
4262 up to date when the user logs off, or the system shuts down.
4263*/
4264BOOL WINAPI shutdown_handler(DWORD type)
4265{
4266 /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them. */
4267 if (type == CTRL_CLOSE_EVENT /* User closes console window. */
4268 || type == CTRL_LOGOFF_EVENT /* User logs off. */
4269 || type == CTRL_SHUTDOWN_EVENT) /* User shutsdown. */
4270 {
4271 /* Shut down cleanly, making sure autosave files are up to date. */
4272 shut_down_emacs (0, 0, Qnil);
4273 }
4274
7046f191 4275 /* Allow other handlers to handle this signal. */
a8c3a596
JR
4276 return FALSE;
4277}
4278
9785d95b
BK
4279/*
4280 globals_of_w32 is used to initialize those global variables that
4281 must always be initialized on startup even when the global variable
4282 initialized is non zero (see the function main in emacs.c).
4283*/
9bfb11f9
KS
4284void
4285globals_of_w32 ()
9785d95b 4286{
74258518
JR
4287 HMODULE kernel32 = GetModuleHandle ("kernel32.dll");
4288
4289 get_process_times_fn = (GetProcessTimes_Proc)
4290 GetProcAddress (kernel32, "GetProcessTimes");
4291
9785d95b
BK
4292 g_b_init_is_windows_9x = 0;
4293 g_b_init_open_process_token = 0;
4294 g_b_init_get_token_information = 0;
4295 g_b_init_lookup_account_sid = 0;
4296 g_b_init_get_sid_identifier_authority = 0;
a8c3a596
JR
4297 /* The following sets a handler for shutdown notifications for
4298 console apps. This actually applies to Emacs in both console and
4299 GUI modes, since we had to fool windows into thinking emacs is a
4300 console application to get console mode to work. */
4301 SetConsoleCtrlHandler(shutdown_handler, TRUE);
9785d95b
BK
4302}
4303
aa5ee2a3 4304/* end of w32.c */
ab5796a9
MB
4305
4306/* arch-tag: 90442dd3-37be-482b-b272-ac752e3049f1
4307 (do not change this comment) */