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