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