(w32_to_x_weight): Return "demibold" instead of "semibold".
[bpt/emacs.git] / src / w32.c
CommitLineData
e9e23e23 1/* Utility and Unix shadow routines for GNU Emacs on the Microsoft W32 API.
35f0d482 2 Copyright (C) 1994, 1995 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 */
38#include "config.h"
39#undef access
40#undef chdir
41#undef chmod
42#undef creat
43#undef ctime
44#undef fopen
45#undef link
46#undef mkdir
47#undef mktemp
48#undef open
49#undef rename
50#undef rmdir
51#undef unlink
52
53#undef close
54#undef dup
55#undef dup2
56#undef pipe
57#undef read
58#undef write
95ed0025 59
95ed0025 60#include "lisp.h"
95ed0025
RS
61
62#include <pwd.h>
63
480b0c5b 64#include <windows.h>
00b3b7b3 65
480b0c5b
GV
66#ifdef HAVE_SOCKETS /* TCP connection support, if kernel can do it */
67#include <sys/socket.h>
68#undef socket
69#undef bind
70#undef connect
71#undef htons
72#undef ntohs
73#undef inet_addr
74#undef gethostname
75#undef gethostbyname
76#undef getservbyname
380961a6 77#undef shutdown
480b0c5b 78#endif
00b3b7b3 79
489f9371 80#include "w32.h"
480b0c5b 81#include "ndir.h"
489f9371 82#include "w32heap.h"
76b3903d 83
03887dd3
KH
84#undef min
85#undef max
86#define min(x, y) (((x) < (y)) ? (x) : (y))
87#define max(x, y) (((x) > (y)) ? (x) : (y))
88
76b3903d
GV
89extern Lisp_Object Vw32_downcase_file_names;
90extern Lisp_Object Vw32_generate_fake_inodes;
91extern Lisp_Object Vw32_get_true_file_attributes;
92
93static char startup_dir[MAXPATHLEN];
00b3b7b3 94
95ed0025 95/* Get the current working directory. */
480b0c5b 96char *
95ed0025
RS
97getwd (char *dir)
98{
76b3903d 99#if 0
480b0c5b
GV
100 if (GetCurrentDirectory (MAXPATHLEN, dir) > 0)
101 return dir;
102 return NULL;
76b3903d
GV
103#else
104 /* Emacs doesn't actually change directory itself, and we want to
105 force our real wd to be where emacs.exe is to avoid unnecessary
106 conflicts when trying to rename or delete directories. */
107 strcpy (dir, startup_dir);
108 return dir;
109#endif
95ed0025
RS
110}
111
480b0c5b 112#ifndef HAVE_SOCKETS
95ed0025
RS
113/* Emulate gethostname. */
114int
115gethostname (char *buffer, int size)
116{
117 /* NT only allows small host names, so the buffer is
118 certainly large enough. */
119 return !GetComputerName (buffer, &size);
120}
480b0c5b 121#endif /* HAVE_SOCKETS */
95ed0025
RS
122
123/* Emulate getloadavg. */
124int
125getloadavg (double loadavg[], int nelem)
126{
127 int i;
128
129 /* A faithful emulation is going to have to be saved for a rainy day. */
130 for (i = 0; i < nelem; i++)
131 {
132 loadavg[i] = 0.0;
133 }
134 return i;
135}
136
480b0c5b 137/* Emulate getpwuid, getpwnam and others. */
95ed0025 138
051fe60d
GV
139#define PASSWD_FIELD_SIZE 256
140
141static char the_passwd_name[PASSWD_FIELD_SIZE];
142static char the_passwd_passwd[PASSWD_FIELD_SIZE];
143static char the_passwd_gecos[PASSWD_FIELD_SIZE];
144static char the_passwd_dir[PASSWD_FIELD_SIZE];
145static char the_passwd_shell[PASSWD_FIELD_SIZE];
95ed0025
RS
146
147static struct passwd the_passwd =
148{
149 the_passwd_name,
150 the_passwd_passwd,
151 0,
152 0,
153 0,
154 the_passwd_gecos,
155 the_passwd_dir,
156 the_passwd_shell,
157};
158
480b0c5b
GV
159int
160getuid ()
161{
162 return the_passwd.pw_uid;
163}
164
165int
166geteuid ()
167{
168 /* I could imagine arguing for checking to see whether the user is
169 in the Administrators group and returning a UID of 0 for that
170 case, but I don't know how wise that would be in the long run. */
171 return getuid ();
172}
173
174int
175getgid ()
176{
177 return the_passwd.pw_gid;
178}
179
180int
181getegid ()
182{
183 return getgid ();
184}
185
95ed0025
RS
186struct passwd *
187getpwuid (int uid)
188{
480b0c5b
GV
189 if (uid == the_passwd.pw_uid)
190 return &the_passwd;
191 return NULL;
95ed0025
RS
192}
193
194struct passwd *
195getpwnam (char *name)
196{
197 struct passwd *pw;
198
199 pw = getpwuid (getuid ());
200 if (!pw)
201 return pw;
202
480b0c5b 203 if (stricmp (name, pw->pw_name))
95ed0025
RS
204 return NULL;
205
206 return pw;
207}
208
480b0c5b
GV
209void
210init_user_info ()
95ed0025 211{
480b0c5b
GV
212 /* Find the user's real name by opening the process token and
213 looking up the name associated with the user-sid in that token.
214
215 Use the relative portion of the identifier authority value from
216 the user-sid as the user id value (same for group id using the
217 primary group sid from the process token). */
218
219 char user_sid[256], name[256], domain[256];
220 DWORD length = sizeof (name), dlength = sizeof (domain), trash;
221 HANDLE token = NULL;
222 SID_NAME_USE user_type;
223
224 if (OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY, &token)
225 && GetTokenInformation (token, TokenUser,
226 (PVOID) user_sid, sizeof (user_sid), &trash)
227 && LookupAccountSid (NULL, *((PSID *) user_sid), name, &length,
228 domain, &dlength, &user_type))
d1c1c3d2 229 {
480b0c5b
GV
230 strcpy (the_passwd.pw_name, name);
231 /* Determine a reasonable uid value. */
232 if (stricmp ("administrator", name) == 0)
233 {
234 the_passwd.pw_uid = 0;
235 the_passwd.pw_gid = 0;
236 }
237 else
238 {
239 SID_IDENTIFIER_AUTHORITY * pSIA;
240
241 pSIA = GetSidIdentifierAuthority (*((PSID *) user_sid));
242 /* I believe the relative portion is the last 4 bytes (of 6)
243 with msb first. */
244 the_passwd.pw_uid = ((pSIA->Value[2] << 24) +
245 (pSIA->Value[3] << 16) +
246 (pSIA->Value[4] << 8) +
247 (pSIA->Value[5] << 0));
248 /* restrict to conventional uid range for normal users */
249 the_passwd.pw_uid = the_passwd.pw_uid % 60001;
250
251 /* Get group id */
252 if (GetTokenInformation (token, TokenPrimaryGroup,
253 (PVOID) user_sid, sizeof (user_sid), &trash))
254 {
255 SID_IDENTIFIER_AUTHORITY * pSIA;
256
257 pSIA = GetSidIdentifierAuthority (*((PSID *) user_sid));
258 the_passwd.pw_gid = ((pSIA->Value[2] << 24) +
259 (pSIA->Value[3] << 16) +
260 (pSIA->Value[4] << 8) +
261 (pSIA->Value[5] << 0));
262 /* I don't know if this is necessary, but for safety... */
263 the_passwd.pw_gid = the_passwd.pw_gid % 60001;
264 }
265 else
266 the_passwd.pw_gid = the_passwd.pw_uid;
267 }
268 }
269 /* If security calls are not supported (presumably because we
270 are running under Windows 95), fallback to this. */
271 else if (GetUserName (name, &length))
272 {
273 strcpy (the_passwd.pw_name, name);
274 if (stricmp ("administrator", name) == 0)
275 the_passwd.pw_uid = 0;
276 else
277 the_passwd.pw_uid = 123;
278 the_passwd.pw_gid = the_passwd.pw_uid;
279 }
280 else
281 {
282 strcpy (the_passwd.pw_name, "unknown");
283 the_passwd.pw_uid = 123;
284 the_passwd.pw_gid = 123;
d1c1c3d2 285 }
95ed0025 286
480b0c5b
GV
287 /* Ensure HOME and SHELL are defined. */
288 if (getenv ("HOME") == NULL)
289 putenv ("HOME=c:/");
290 if (getenv ("SHELL") == NULL)
76b3903d 291 putenv (os_subtype == OS_WIN95 ? "SHELL=command" : "SHELL=cmd");
95ed0025 292
480b0c5b
GV
293 /* Set dir and shell from environment variables. */
294 strcpy (the_passwd.pw_dir, getenv ("HOME"));
295 strcpy (the_passwd.pw_shell, getenv ("SHELL"));
bd4a449f 296
480b0c5b
GV
297 if (token)
298 CloseHandle (token);
95ed0025
RS
299}
300
95ed0025 301int
480b0c5b 302random ()
95ed0025 303{
480b0c5b
GV
304 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
305 return ((rand () << 15) | rand ());
95ed0025
RS
306}
307
95ed0025 308void
480b0c5b 309srandom (int seed)
95ed0025 310{
480b0c5b 311 srand (seed);
95ed0025
RS
312}
313
76b3903d 314
cbe39279
RS
315/* Normalize filename by converting all path separators to
316 the specified separator. Also conditionally convert upper
317 case path name components to lower case. */
318
319static void
320normalize_filename (fp, path_sep)
321 register char *fp;
322 char path_sep;
323{
324 char sep;
325 char *elem;
326
5162ffce
MB
327 /* Always lower-case drive letters a-z, even if the filesystem
328 preserves case in filenames.
329 This is so filenames can be compared by string comparison
330 functions that are case-sensitive. Even case-preserving filesystems
331 do not distinguish case in drive letters. */
332 if (fp[1] == ':' && *fp >= 'A' && *fp <= 'Z')
333 {
334 *fp += 'a' - 'A';
335 fp += 2;
336 }
337
fbd6baed 338 if (NILP (Vw32_downcase_file_names))
cbe39279
RS
339 {
340 while (*fp)
341 {
342 if (*fp == '/' || *fp == '\\')
343 *fp = path_sep;
344 fp++;
345 }
346 return;
347 }
348
349 sep = path_sep; /* convert to this path separator */
350 elem = fp; /* start of current path element */
351
352 do {
353 if (*fp >= 'a' && *fp <= 'z')
354 elem = 0; /* don't convert this element */
355
356 if (*fp == 0 || *fp == ':')
357 {
358 sep = *fp; /* restore current separator (or 0) */
359 *fp = '/'; /* after conversion of this element */
360 }
361
362 if (*fp == '/' || *fp == '\\')
363 {
364 if (elem && elem != fp)
365 {
366 *fp = 0; /* temporary end of string */
367 _strlwr (elem); /* while we convert to lower case */
368 }
369 *fp = sep; /* convert (or restore) path separator */
370 elem = fp + 1; /* next element starts after separator */
371 sep = path_sep;
372 }
373 } while (*fp++);
374}
375
480b0c5b 376/* Destructively turn backslashes into slashes. */
95ed0025 377void
480b0c5b
GV
378dostounix_filename (p)
379 register char *p;
95ed0025 380{
cbe39279 381 normalize_filename (p, '/');
95ed0025
RS
382}
383
480b0c5b 384/* Destructively turn slashes into backslashes. */
95ed0025 385void
480b0c5b
GV
386unixtodos_filename (p)
387 register char *p;
95ed0025 388{
cbe39279 389 normalize_filename (p, '\\');
95ed0025
RS
390}
391
480b0c5b
GV
392/* Remove all CR's that are followed by a LF.
393 (From msdos.c...probably should figure out a way to share it,
394 although this code isn't going to ever change.) */
35f0d482 395int
480b0c5b
GV
396crlf_to_lf (n, buf)
397 register int n;
398 register unsigned char *buf;
35f0d482 399{
480b0c5b
GV
400 unsigned char *np = buf;
401 unsigned char *startp = buf;
402 unsigned char *endp = buf + n;
35f0d482 403
480b0c5b
GV
404 if (n == 0)
405 return n;
406 while (buf < endp - 1)
95ed0025 407 {
480b0c5b
GV
408 if (*buf == 0x0d)
409 {
410 if (*(++buf) != 0x0a)
411 *np++ = 0x0d;
412 }
413 else
414 *np++ = *buf++;
95ed0025 415 }
480b0c5b
GV
416 if (buf < endp)
417 *np++ = *buf++;
418 return np - startp;
95ed0025
RS
419}
420
76b3903d
GV
421/* Parse the root part of file name, if present. Return length and
422 optionally store pointer to char after root. */
423static int
424parse_root (char * name, char ** pPath)
425{
426 char * start = name;
427
428 if (name == NULL)
429 return 0;
430
431 /* find the root name of the volume if given */
432 if (isalpha (name[0]) && name[1] == ':')
433 {
434 /* skip past drive specifier */
435 name += 2;
436 if (IS_DIRECTORY_SEP (name[0]))
437 name++;
438 }
439 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
440 {
441 int slashes = 2;
442 name += 2;
443 do
444 {
445 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
446 break;
447 name++;
448 }
449 while ( *name );
450 if (IS_DIRECTORY_SEP (name[0]))
451 name++;
452 }
453
454 if (pPath)
455 *pPath = name;
456
457 return name - start;
458}
459
460/* Get long base name for name; name is assumed to be absolute. */
461static int
462get_long_basename (char * name, char * buf, int size)
463{
464 WIN32_FIND_DATA find_data;
465 HANDLE dir_handle;
466 int len = 0;
467
bb1584c8
RS
468 /* must be valid filename, no wild cards or other illegal characters */
469 if (strpbrk (name, "*?|<>\""))
470 return 0;
471
76b3903d
GV
472 dir_handle = FindFirstFile (name, &find_data);
473 if (dir_handle != INVALID_HANDLE_VALUE)
474 {
475 if ((len = strlen (find_data.cFileName)) < size)
476 memcpy (buf, find_data.cFileName, len + 1);
477 else
478 len = 0;
479 FindClose (dir_handle);
480 }
481 return len;
482}
483
484/* Get long name for file, if possible (assumed to be absolute). */
485BOOL
486w32_get_long_filename (char * name, char * buf, int size)
487{
488 char * o = buf;
489 char * p;
490 char * q;
491 char full[ MAX_PATH ];
492 int len;
493
494 len = strlen (name);
495 if (len >= MAX_PATH)
496 return FALSE;
497
498 /* Use local copy for destructive modification. */
499 memcpy (full, name, len+1);
500 unixtodos_filename (full);
501
502 /* Copy root part verbatim. */
503 len = parse_root (full, &p);
504 memcpy (o, full, len);
505 o += len;
4f8ac0b2 506 *o = '\0';
76b3903d
GV
507 size -= len;
508
4f8ac0b2 509 while (p != NULL && *p)
76b3903d
GV
510 {
511 q = p;
512 p = strchr (q, '\\');
513 if (p) *p = '\0';
514 len = get_long_basename (full, o, size);
515 if (len > 0)
516 {
517 o += len;
518 size -= len;
519 if (p != NULL)
520 {
521 *p++ = '\\';
522 if (size < 2)
523 return FALSE;
524 *o++ = '\\';
525 size--;
526 *o = '\0';
527 }
528 }
529 else
530 return FALSE;
531 }
76b3903d
GV
532
533 return TRUE;
534}
535
9d3355d1
GV
536int
537is_unc_volume (const char *filename)
538{
539 const char *ptr = filename;
540
541 if (!IS_DIRECTORY_SEP (ptr[0]) || !IS_DIRECTORY_SEP (ptr[1]) || !ptr[2])
542 return 0;
543
544 if (strpbrk (ptr + 2, "*?|<>\"\\/"))
545 return 0;
546
547 return 1;
548}
76b3903d 549
95ed0025
RS
550/* Routines that are no-ops on NT but are defined to get Emacs to compile. */
551
95ed0025
RS
552int
553sigsetmask (int signal_mask)
554{
555 return 0;
556}
557
558int
559sigblock (int sig)
560{
561 return 0;
562}
563
95ed0025
RS
564int
565setpgrp (int pid, int gid)
566{
567 return 0;
568}
569
570int
571alarm (int seconds)
572{
573 return 0;
574}
575
c6624584 576void
95ed0025
RS
577unrequest_sigio (void)
578{
c6624584 579 return;
95ed0025
RS
580}
581
c6624584 582void
95ed0025
RS
583request_sigio (void)
584{
c6624584 585 return;
95ed0025
RS
586}
587
480b0c5b 588#define REG_ROOT "SOFTWARE\\GNU\\Emacs"
f332b293
GV
589
590LPBYTE
fbd6baed 591w32_get_resource (key, lpdwtype)
f332b293
GV
592 char *key;
593 LPDWORD lpdwtype;
594{
595 LPBYTE lpvalue;
596 HKEY hrootkey = NULL;
597 DWORD cbData;
598 BOOL ok = FALSE;
599
600 /* Check both the current user and the local machine to see if
601 we have any resources. */
602
603 if (RegOpenKeyEx (HKEY_CURRENT_USER, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
604 {
605 lpvalue = NULL;
606
607 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
608 && (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL
609 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
610 {
611 return (lpvalue);
612 }
613
614 if (lpvalue) xfree (lpvalue);
615
616 RegCloseKey (hrootkey);
617 }
618
619 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
620 {
621 lpvalue = NULL;
622
76b3903d
GV
623 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
624 && (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL
625 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
f332b293
GV
626 {
627 return (lpvalue);
628 }
629
630 if (lpvalue) xfree (lpvalue);
631
632 RegCloseKey (hrootkey);
633 }
634
635 return (NULL);
636}
637
75b08edb
GV
638char *get_emacs_configuration (void);
639extern Lisp_Object Vsystem_configuration;
640
f332b293 641void
aa7b87b0 642init_environment (char ** argv)
f332b293 643{
b3308d2e
KH
644 int len;
645 static const char * const tempdirs[] = {
646 "$TMPDIR", "$TEMP", "$TMP", "c:/"
647 };
648 int i;
649 const int imax = sizeof (tempdirs) / sizeof (tempdirs[0]);
650
651 /* Make sure they have a usable $TMPDIR. Many Emacs functions use
652 temporary files and assume "/tmp" if $TMPDIR is unset, which
653 will break on DOS/Windows. Refuse to work if we cannot find
654 a directory, not even "c:/", usable for that purpose. */
655 for (i = 0; i < imax ; i++)
656 {
657 const char *tmp = tempdirs[i];
658
659 if (*tmp == '$')
660 tmp = getenv (tmp + 1);
661 /* Note that `access' can lie to us if the directory resides on a
662 read-only filesystem, like CD-ROM or a write-protected floppy.
663 The only way to be really sure is to actually create a file and
664 see if it succeeds. But I think that's too much to ask. */
665 if (tmp && access (tmp, D_OK) == 0)
666 {
667 char * var = alloca (strlen (tmp) + 8);
668 sprintf (var, "TMPDIR=%s", tmp);
669 putenv (var);
670 break;
671 }
672 }
673 if (i >= imax)
674 cmd_error_internal
675 (Fcons (Qerror,
676 Fcons (build_string ("no usable temporary directories found!!"),
677 Qnil)),
678 "While setting TMPDIR: ");
679
f332b293
GV
680 /* Check for environment variables and use registry if they don't exist */
681 {
480b0c5b
GV
682 int i;
683 LPBYTE lpval;
684 DWORD dwType;
f332b293 685
480b0c5b
GV
686 static char * env_vars[] =
687 {
688 "HOME",
f249a012 689 "PRELOAD_WINSOCK",
480b0c5b
GV
690 "emacs_dir",
691 "EMACSLOADPATH",
692 "SHELL",
76b3903d 693 "CMDPROXY",
480b0c5b
GV
694 "EMACSDATA",
695 "EMACSPATH",
696 "EMACSLOCKDIR",
76b3903d
GV
697 /* We no longer set INFOPATH because Info-default-directory-list
698 is then ignored. We use a hook in winnt.el instead. */
699 /* "INFOPATH", */
480b0c5b
GV
700 "EMACSDOC",
701 "TERM",
702 };
703
704 for (i = 0; i < (sizeof (env_vars) / sizeof (env_vars[0])); i++)
f332b293 705 {
76b3903d
GV
706 if (!getenv (env_vars[i])
707 && (lpval = w32_get_resource (env_vars[i], &dwType)) != NULL)
480b0c5b
GV
708 {
709 if (dwType == REG_EXPAND_SZ)
710 {
711 char buf1[500], buf2[500];
712
713 ExpandEnvironmentStrings ((LPSTR) lpval, buf1, 500);
714 _snprintf (buf2, 499, "%s=%s", env_vars[i], buf1);
715 putenv (strdup (buf2));
716 }
717 else if (dwType == REG_SZ)
718 {
719 char buf[500];
f332b293 720
480b0c5b
GV
721 _snprintf (buf, 499, "%s=%s", env_vars[i], lpval);
722 putenv (strdup (buf));
723 }
f332b293 724
480b0c5b
GV
725 xfree (lpval);
726 }
727 }
728 }
729
75b08edb
GV
730 /* Rebuild system configuration to reflect invoking system. */
731 Vsystem_configuration = build_string (EMACS_CONFIGURATION);
732
76b3903d
GV
733 /* Another special case: on NT, the PATH variable is actually named
734 "Path" although cmd.exe (perhaps NT itself) arranges for
735 environment variable lookup and setting to be case insensitive.
736 However, Emacs assumes a fully case sensitive environment, so we
737 need to change "Path" to "PATH" to match the expectations of
738 various elisp packages. We do this by the sneaky method of
739 modifying the string in the C runtime environ entry.
740
741 The same applies to COMSPEC. */
742 {
743 char ** envp;
744
745 for (envp = environ; *envp; envp++)
746 if (_strnicmp (*envp, "PATH=", 5) == 0)
747 memcpy (*envp, "PATH=", 5);
748 else if (_strnicmp (*envp, "COMSPEC=", 8) == 0)
749 memcpy (*envp, "COMSPEC=", 8);
750 }
751
752 /* Remember the initial working directory for getwd, then make the
753 real wd be the location of emacs.exe to avoid conflicts when
754 renaming or deleting directories. (We also don't call chdir when
755 running subprocesses for the same reason.) */
756 if (!GetCurrentDirectory (MAXPATHLEN, startup_dir))
757 abort ();
758
759 {
760 char *p;
aa7b87b0 761 static char modname[MAX_PATH];
76b3903d
GV
762
763 if (!GetModuleFileName (NULL, modname, MAX_PATH))
764 abort ();
765 if ((p = strrchr (modname, '\\')) == NULL)
766 abort ();
767 *p = 0;
768
769 SetCurrentDirectory (modname);
aa7b87b0
AI
770
771 /* Ensure argv[0] has the full path to Emacs. */
772 *p = '\\';
773 argv[0] = modname;
76b3903d
GV
774 }
775
480b0c5b
GV
776 init_user_info ();
777}
778
779/* We don't have scripts to automatically determine the system configuration
780 for Emacs before it's compiled, and we don't want to have to make the
781 user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
782 routine. */
783
784static char configuration_buffer[32];
785
786char *
787get_emacs_configuration (void)
788{
789 char *arch, *oem, *os;
790
791 /* Determine the processor type. */
792 switch (get_processor_type ())
793 {
794
795#ifdef PROCESSOR_INTEL_386
796 case PROCESSOR_INTEL_386:
797 case PROCESSOR_INTEL_486:
798 case PROCESSOR_INTEL_PENTIUM:
799 arch = "i386";
800 break;
801#endif
802
803#ifdef PROCESSOR_INTEL_860
804 case PROCESSOR_INTEL_860:
805 arch = "i860";
806 break;
807#endif
808
809#ifdef PROCESSOR_MIPS_R2000
810 case PROCESSOR_MIPS_R2000:
811 case PROCESSOR_MIPS_R3000:
812 case PROCESSOR_MIPS_R4000:
813 arch = "mips";
814 break;
815#endif
816
817#ifdef PROCESSOR_ALPHA_21064
818 case PROCESSOR_ALPHA_21064:
819 arch = "alpha";
820 break;
821#endif
822
823 default:
824 arch = "unknown";
825 break;
f332b293 826 }
480b0c5b
GV
827
828 /* Let oem be "*" until we figure out how to decode the OEM field. */
829 oem = "*";
830
76b3903d 831 os = (GetVersion () & OS_WIN95) ? "windows95" : "nt";
480b0c5b
GV
832
833 sprintf (configuration_buffer, "%s-%s-%s%d.%d", arch, oem, os,
fbd6baed 834 get_w32_major_version (), get_w32_minor_version ());
480b0c5b 835 return configuration_buffer;
f332b293
GV
836}
837
35f0d482
KH
838#include <sys/timeb.h>
839
840/* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
841void
842gettimeofday (struct timeval *tv, struct timezone *tz)
843{
844 struct _timeb tb;
845 _ftime (&tb);
846
847 tv->tv_sec = tb.time;
848 tv->tv_usec = tb.millitm * 1000L;
849 if (tz)
850 {
851 tz->tz_minuteswest = tb.timezone; /* minutes west of Greenwich */
852 tz->tz_dsttime = tb.dstflag; /* type of dst correction */
853 }
854}
35f0d482 855
480b0c5b 856/* ------------------------------------------------------------------------- */
fbd6baed 857/* IO support and wrapper functions for W32 API. */
480b0c5b 858/* ------------------------------------------------------------------------- */
95ed0025 859
480b0c5b
GV
860/* Place a wrapper around the MSVC version of ctime. It returns NULL
861 on network directories, so we handle that case here.
862 (Ulrich Leodolter, 1/11/95). */
863char *
864sys_ctime (const time_t *t)
865{
866 char *str = (char *) ctime (t);
867 return (str ? str : "Sun Jan 01 00:00:00 1970");
868}
869
870/* Emulate sleep...we could have done this with a define, but that
871 would necessitate including windows.h in the files that used it.
872 This is much easier. */
873void
874sys_sleep (int seconds)
875{
876 Sleep (seconds * 1000);
877}
878
76b3903d 879/* Internal MSVC functions for low-level descriptor munging */
480b0c5b
GV
880extern int __cdecl _set_osfhnd (int fd, long h);
881extern int __cdecl _free_osfhnd (int fd);
882
883/* parallel array of private info on file handles */
884filedesc fd_info [ MAXDESC ];
885
76b3903d
GV
886typedef struct volume_info_data {
887 struct volume_info_data * next;
888
889 /* time when info was obtained */
890 DWORD timestamp;
891
892 /* actual volume info */
893 char * root_dir;
480b0c5b
GV
894 DWORD serialnum;
895 DWORD maxcomp;
896 DWORD flags;
76b3903d
GV
897 char * name;
898 char * type;
899} volume_info_data;
900
901/* Global referenced by various functions. */
902static volume_info_data volume_info;
903
904/* Vector to indicate which drives are local and fixed (for which cached
905 data never expires). */
906static BOOL fixed_drives[26];
907
908/* Consider cached volume information to be stale if older than 10s,
909 at least for non-local drives. Info for fixed drives is never stale. */
910#define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
911#define VOLINFO_STILL_VALID( root_dir, info ) \
912 ( ( isalpha (root_dir[0]) && \
913 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
914 || GetTickCount () - info->timestamp < 10000 )
915
916/* Cache support functions. */
917
918/* Simple linked list with linear search is sufficient. */
919static volume_info_data *volume_cache = NULL;
920
921static volume_info_data *
922lookup_volume_info (char * root_dir)
923{
924 volume_info_data * info;
925
926 for (info = volume_cache; info; info = info->next)
927 if (stricmp (info->root_dir, root_dir) == 0)
928 break;
929 return info;
930}
931
932static void
933add_volume_info (char * root_dir, volume_info_data * info)
934{
935 info->root_dir = strdup (root_dir);
936 info->next = volume_cache;
937 volume_cache = info;
938}
939
940
941/* Wrapper for GetVolumeInformation, which uses caching to avoid
942 performance penalty (~2ms on 486 for local drives, 7.5ms for local
943 cdrom drive, ~5-10ms or more for remote drives on LAN). */
944volume_info_data *
945GetCachedVolumeInformation (char * root_dir)
946{
947 volume_info_data * info;
948 char default_root[ MAX_PATH ];
949
950 /* NULL for root_dir means use root from current directory. */
951 if (root_dir == NULL)
952 {
953 if (GetCurrentDirectory (MAX_PATH, default_root) == 0)
954 return NULL;
955 parse_root (default_root, &root_dir);
956 *root_dir = 0;
957 root_dir = default_root;
958 }
959
960 /* Local fixed drives can be cached permanently. Removable drives
961 cannot be cached permanently, since the volume name and serial
962 number (if nothing else) can change. Remote drives should be
963 treated as if they are removable, since there is no sure way to
964 tell whether they are or not. Also, the UNC association of drive
965 letters mapped to remote volumes can be changed at any time (even
966 by other processes) without notice.
967
968 As a compromise, so we can benefit from caching info for remote
969 volumes, we use a simple expiry mechanism to invalidate cache
970 entries that are more than ten seconds old. */
971
972#if 0
973 /* No point doing this, because WNetGetConnection is even slower than
974 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
975 GetDriveType is about the only call of this type which does not
976 involve network access, and so is extremely quick). */
977
978 /* Map drive letter to UNC if remote. */
979 if ( isalpha( root_dir[0] ) && !fixed[ DRIVE_INDEX( root_dir[0] ) ] )
980 {
981 char remote_name[ 256 ];
982 char drive[3] = { root_dir[0], ':' };
983
984 if (WNetGetConnection (drive, remote_name, sizeof (remote_name))
985 == NO_ERROR)
986 /* do something */ ;
987 }
988#endif
989
990 info = lookup_volume_info (root_dir);
991
992 if (info == NULL || ! VOLINFO_STILL_VALID (root_dir, info))
993 {
994 char name[ 256 ];
995 DWORD serialnum;
996 DWORD maxcomp;
997 DWORD flags;
998 char type[ 256 ];
999
1000 /* Info is not cached, or is stale. */
1001 if (!GetVolumeInformation (root_dir,
1002 name, sizeof (name),
1003 &serialnum,
1004 &maxcomp,
1005 &flags,
1006 type, sizeof (type)))
1007 return NULL;
1008
1009 /* Cache the volume information for future use, overwriting existing
1010 entry if present. */
1011 if (info == NULL)
1012 {
1013 info = (volume_info_data *) xmalloc (sizeof (volume_info_data));
1014 add_volume_info (root_dir, info);
1015 }
1016 else
1017 {
1018 free (info->name);
1019 free (info->type);
1020 }
1021
1022 info->name = strdup (name);
1023 info->serialnum = serialnum;
1024 info->maxcomp = maxcomp;
1025 info->flags = flags;
1026 info->type = strdup (type);
1027 info->timestamp = GetTickCount ();
1028 }
1029
1030 return info;
1031}
480b0c5b
GV
1032
1033/* Get information on the volume where name is held; set path pointer to
1034 start of pathname in name (past UNC header\volume header if present). */
1035int
1036get_volume_info (const char * name, const char ** pPath)
95ed0025 1037{
480b0c5b
GV
1038 char temp[MAX_PATH];
1039 char *rootname = NULL; /* default to current volume */
76b3903d 1040 volume_info_data * info;
480b0c5b
GV
1041
1042 if (name == NULL)
1043 return FALSE;
1044
1045 /* find the root name of the volume if given */
1046 if (isalpha (name[0]) && name[1] == ':')
1047 {
1048 rootname = temp;
1049 temp[0] = *name++;
1050 temp[1] = *name++;
1051 temp[2] = '\\';
1052 temp[3] = 0;
1053 }
1054 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
95ed0025 1055 {
480b0c5b
GV
1056 char *str = temp;
1057 int slashes = 4;
1058 rootname = temp;
1059 do
1060 {
1061 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
1062 break;
1063 *str++ = *name++;
1064 }
1065 while ( *name );
1066
480b0c5b
GV
1067 *str++ = '\\';
1068 *str = 0;
95ed0025 1069 }
480b0c5b
GV
1070
1071 if (pPath)
1072 *pPath = name;
1073
76b3903d
GV
1074 info = GetCachedVolumeInformation (rootname);
1075 if (info != NULL)
95ed0025 1076 {
76b3903d
GV
1077 /* Set global referenced by other functions. */
1078 volume_info = *info;
480b0c5b 1079 return TRUE;
95ed0025 1080 }
480b0c5b
GV
1081 return FALSE;
1082}
1083
1084/* Determine if volume is FAT format (ie. only supports short 8.3
1085 names); also set path pointer to start of pathname in name. */
1086int
1087is_fat_volume (const char * name, const char ** pPath)
1088{
1089 if (get_volume_info (name, pPath))
1090 return (volume_info.maxcomp == 12);
1091 return FALSE;
1092}
1093
1094/* Map filename to a legal 8.3 name if necessary. */
1095const char *
fbd6baed 1096map_w32_filename (const char * name, const char ** pPath)
480b0c5b
GV
1097{
1098 static char shortname[MAX_PATH];
1099 char * str = shortname;
1100 char c;
480b0c5b 1101 char * path;
76b3903d 1102 const char * save_name = name;
480b0c5b
GV
1103
1104 if (is_fat_volume (name, &path)) /* truncate to 8.3 */
95ed0025 1105 {
480b0c5b
GV
1106 register int left = 8; /* maximum number of chars in part */
1107 register int extn = 0; /* extension added? */
1108 register int dots = 2; /* maximum number of dots allowed */
1109
1110 while (name < path)
1111 *str++ = *name++; /* skip past UNC header */
1112
1113 while ((c = *name++))
1114 {
1115 switch ( c )
1116 {
1117 case '\\':
1118 case '/':
1119 *str++ = '\\';
1120 extn = 0; /* reset extension flags */
1121 dots = 2; /* max 2 dots */
1122 left = 8; /* max length 8 for main part */
1123 break;
1124 case ':':
1125 *str++ = ':';
1126 extn = 0; /* reset extension flags */
1127 dots = 2; /* max 2 dots */
1128 left = 8; /* max length 8 for main part */
1129 break;
1130 case '.':
1131 if ( dots )
1132 {
1133 /* Convert path components of the form .xxx to _xxx,
1134 but leave . and .. as they are. This allows .emacs
1135 to be read as _emacs, for example. */
1136
1137 if (! *name ||
1138 *name == '.' ||
1139 IS_DIRECTORY_SEP (*name))
1140 {
1141 *str++ = '.';
1142 dots--;
1143 }
1144 else
1145 {
1146 *str++ = '_';
1147 left--;
1148 dots = 0;
1149 }
1150 }
1151 else if ( !extn )
1152 {
1153 *str++ = '.';
1154 extn = 1; /* we've got an extension */
1155 left = 3; /* 3 chars in extension */
1156 }
1157 else
1158 {
1159 /* any embedded dots after the first are converted to _ */
1160 *str++ = '_';
1161 }
1162 break;
1163 case '~':
1164 case '#': /* don't lose these, they're important */
1165 if ( ! left )
1166 str[-1] = c; /* replace last character of part */
1167 /* FALLTHRU */
1168 default:
1169 if ( left )
1170 {
1171 *str++ = tolower (c); /* map to lower case (looks nicer) */
1172 left--;
1173 dots = 0; /* started a path component */
1174 }
1175 break;
1176 }
1177 }
1178 *str = '\0';
fc85cb29
RS
1179 }
1180 else
1181 {
1182 strcpy (shortname, name);
1183 unixtodos_filename (shortname);
95ed0025 1184 }
480b0c5b
GV
1185
1186 if (pPath)
76b3903d 1187 *pPath = shortname + (path - save_name);
480b0c5b 1188
fc85cb29 1189 return shortname;
480b0c5b
GV
1190}
1191
b3308d2e
KH
1192static int
1193is_exec (const char * name)
1194{
1195 char * p = strrchr (name, '.');
1196 return
1197 (p != NULL
1198 && (stricmp (p, ".exe") == 0 ||
1199 stricmp (p, ".com") == 0 ||
1200 stricmp (p, ".bat") == 0 ||
1201 stricmp (p, ".cmd") == 0));
1202}
1203
76b3903d
GV
1204/* Emulate the Unix directory procedures opendir, closedir,
1205 and readdir. We can't use the procedures supplied in sysdep.c,
1206 so we provide them here. */
1207
1208struct direct dir_static; /* simulated directory contents */
1209static HANDLE dir_find_handle = INVALID_HANDLE_VALUE;
1210static int dir_is_fat;
1211static char dir_pathname[MAXPATHLEN+1];
1212static WIN32_FIND_DATA dir_find_data;
1213
9d3355d1
GV
1214/* Support shares on a network resource as subdirectories of a read-only
1215 root directory. */
1216static HANDLE wnet_enum_handle = INVALID_HANDLE_VALUE;
1217HANDLE open_unc_volume (char *);
1218char *read_unc_volume (HANDLE, char *, int);
1219void close_unc_volume (HANDLE);
1220
76b3903d
GV
1221DIR *
1222opendir (char *filename)
1223{
1224 DIR *dirp;
1225
1226 /* Opening is done by FindFirstFile. However, a read is inherent to
1227 this operation, so we defer the open until read time. */
1228
76b3903d
GV
1229 if (dir_find_handle != INVALID_HANDLE_VALUE)
1230 return NULL;
9d3355d1
GV
1231 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
1232 return NULL;
1233
1234 if (is_unc_volume (filename))
1235 {
1236 wnet_enum_handle = open_unc_volume (filename);
1237 if (wnet_enum_handle == INVALID_HANDLE_VALUE)
1238 return NULL;
1239 }
1240
1241 if (!(dirp = (DIR *) malloc (sizeof (DIR))))
1242 return NULL;
76b3903d
GV
1243
1244 dirp->dd_fd = 0;
1245 dirp->dd_loc = 0;
1246 dirp->dd_size = 0;
1247
1248 strncpy (dir_pathname, map_w32_filename (filename, NULL), MAXPATHLEN);
1249 dir_pathname[MAXPATHLEN] = '\0';
1250 dir_is_fat = is_fat_volume (filename, NULL);
1251
1252 return dirp;
1253}
1254
1255void
1256closedir (DIR *dirp)
1257{
1258 /* If we have a find-handle open, close it. */
1259 if (dir_find_handle != INVALID_HANDLE_VALUE)
1260 {
1261 FindClose (dir_find_handle);
1262 dir_find_handle = INVALID_HANDLE_VALUE;
1263 }
9d3355d1
GV
1264 else if (wnet_enum_handle != INVALID_HANDLE_VALUE)
1265 {
1266 close_unc_volume (wnet_enum_handle);
1267 wnet_enum_handle = INVALID_HANDLE_VALUE;
1268 }
76b3903d
GV
1269 xfree ((char *) dirp);
1270}
1271
1272struct direct *
1273readdir (DIR *dirp)
1274{
9d3355d1
GV
1275 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
1276 {
1277 if (!read_unc_volume (wnet_enum_handle,
1278 dir_find_data.cFileName,
1279 MAX_PATH))
1280 return NULL;
1281 }
76b3903d 1282 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
9d3355d1 1283 else if (dir_find_handle == INVALID_HANDLE_VALUE)
76b3903d
GV
1284 {
1285 char filename[MAXNAMLEN + 3];
1286 int ln;
1287
1288 strcpy (filename, dir_pathname);
1289 ln = strlen (filename) - 1;
1290 if (!IS_DIRECTORY_SEP (filename[ln]))
1291 strcat (filename, "\\");
1292 strcat (filename, "*");
1293
1294 dir_find_handle = FindFirstFile (filename, &dir_find_data);
1295
1296 if (dir_find_handle == INVALID_HANDLE_VALUE)
1297 return NULL;
1298 }
1299 else
1300 {
1301 if (!FindNextFile (dir_find_handle, &dir_find_data))
1302 return NULL;
1303 }
1304
1305 /* Emacs never uses this value, so don't bother making it match
1306 value returned by stat(). */
1307 dir_static.d_ino = 1;
1308
1309 dir_static.d_reclen = sizeof (struct direct) - MAXNAMLEN + 3 +
1310 dir_static.d_namlen - dir_static.d_namlen % 4;
1311
1312 dir_static.d_namlen = strlen (dir_find_data.cFileName);
1313 strcpy (dir_static.d_name, dir_find_data.cFileName);
1314 if (dir_is_fat)
1315 _strlwr (dir_static.d_name);
1316 else if (!NILP (Vw32_downcase_file_names))
1317 {
1318 register char *p;
1319 for (p = dir_static.d_name; *p; p++)
1320 if (*p >= 'a' && *p <= 'z')
1321 break;
1322 if (!*p)
1323 _strlwr (dir_static.d_name);
1324 }
1325
1326 return &dir_static;
1327}
1328
9d3355d1
GV
1329HANDLE
1330open_unc_volume (char *path)
1331{
1332 NETRESOURCE nr;
1333 HANDLE henum;
1334 int result;
1335
1336 nr.dwScope = RESOURCE_GLOBALNET;
1337 nr.dwType = RESOURCETYPE_DISK;
1338 nr.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
1339 nr.dwUsage = RESOURCEUSAGE_CONTAINER;
1340 nr.lpLocalName = NULL;
1341 nr.lpRemoteName = map_w32_filename (path, NULL);
1342 nr.lpComment = NULL;
1343 nr.lpProvider = NULL;
1344
1345 result = WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
1346 RESOURCEUSAGE_CONNECTABLE, &nr, &henum);
1347
1348 if (result == NO_ERROR)
1349 return henum;
1350 else
1351 return INVALID_HANDLE_VALUE;
1352}
1353
1354char *
1355read_unc_volume (HANDLE henum, char *readbuf, int size)
1356{
1357 int count;
1358 int result;
1359 int bufsize = 512;
1360 char *buffer;
1361 char *ptr;
1362
1363 count = 1;
1364 buffer = alloca (bufsize);
1365 result = WNetEnumResource (wnet_enum_handle, &count, buffer, &bufsize);
1366 if (result != NO_ERROR)
1367 return NULL;
1368
1369 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
1370 ptr = ((LPNETRESOURCE) buffer)->lpRemoteName;
1371 ptr += 2;
1372 while (*ptr && !IS_DIRECTORY_SEP (*ptr)) ptr++;
1373 ptr++;
1374
1375 strncpy (readbuf, ptr, size);
1376 return readbuf;
1377}
1378
1379void
1380close_unc_volume (HANDLE henum)
1381{
1382 if (henum != INVALID_HANDLE_VALUE)
1383 WNetCloseEnum (henum);
1384}
1385
1386DWORD
1387unc_volume_file_attributes (char *path)
1388{
1389 HANDLE henum;
1390 DWORD attrs;
1391
1392 henum = open_unc_volume (path);
1393 if (henum == INVALID_HANDLE_VALUE)
1394 return -1;
1395
1396 attrs = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY;
1397
1398 close_unc_volume (henum);
1399
1400 return attrs;
1401}
1402
480b0c5b
GV
1403
1404/* Shadow some MSVC runtime functions to map requests for long filenames
1405 to reasonable short names if necessary. This was originally added to
1406 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
1407 long file names. */
1408
1409int
1410sys_access (const char * path, int mode)
1411{
b3308d2e
KH
1412 DWORD attributes;
1413
1414 /* MSVC implementation doesn't recognize D_OK. */
1415 path = map_w32_filename (path, NULL);
9d3355d1
GV
1416 if (is_unc_volume (path))
1417 {
1418 attributes = unc_volume_file_attributes (path);
1419 if (attributes == -1) {
1420 errno = EACCES;
1421 return -1;
1422 }
1423 }
1424 else if ((attributes = GetFileAttributes (path)) == -1)
b3308d2e
KH
1425 {
1426 /* Should try mapping GetLastError to errno; for now just indicate
1427 that path doesn't exist. */
1428 errno = EACCES;
1429 return -1;
1430 }
1431 if ((mode & X_OK) != 0 && !is_exec (path))
1432 {
1433 errno = EACCES;
1434 return -1;
1435 }
1436 if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0)
1437 {
1438 errno = EACCES;
1439 return -1;
1440 }
1441 if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
1442 {
1443 errno = EACCES;
1444 return -1;
1445 }
1446 return 0;
480b0c5b
GV
1447}
1448
1449int
1450sys_chdir (const char * path)
1451{
fbd6baed 1452 return _chdir (map_w32_filename (path, NULL));
480b0c5b
GV
1453}
1454
1455int
1456sys_chmod (const char * path, int mode)
1457{
fbd6baed 1458 return _chmod (map_w32_filename (path, NULL), mode);
480b0c5b
GV
1459}
1460
1461int
1462sys_creat (const char * path, int mode)
1463{
fbd6baed 1464 return _creat (map_w32_filename (path, NULL), mode);
480b0c5b
GV
1465}
1466
1467FILE *
1468sys_fopen(const char * path, const char * mode)
1469{
1470 int fd;
1471 int oflag;
1472 const char * mode_save = mode;
1473
1474 /* Force all file handles to be non-inheritable. This is necessary to
1475 ensure child processes don't unwittingly inherit handles that might
1476 prevent future file access. */
1477
1478 if (mode[0] == 'r')
1479 oflag = O_RDONLY;
1480 else if (mode[0] == 'w' || mode[0] == 'a')
1481 oflag = O_WRONLY | O_CREAT | O_TRUNC;
95ed0025 1482 else
480b0c5b
GV
1483 return NULL;
1484
1485 /* Only do simplistic option parsing. */
1486 while (*++mode)
1487 if (mode[0] == '+')
1488 {
1489 oflag &= ~(O_RDONLY | O_WRONLY);
1490 oflag |= O_RDWR;
1491 }
1492 else if (mode[0] == 'b')
1493 {
1494 oflag &= ~O_TEXT;
1495 oflag |= O_BINARY;
1496 }
1497 else if (mode[0] == 't')
1498 {
1499 oflag &= ~O_BINARY;
1500 oflag |= O_TEXT;
1501 }
1502 else break;
1503
fbd6baed 1504 fd = _open (map_w32_filename (path, NULL), oflag | _O_NOINHERIT, 0644);
480b0c5b
GV
1505 if (fd < 0)
1506 return NULL;
1507
76b3903d 1508 return _fdopen (fd, mode_save);
95ed0025 1509}
480b0c5b 1510
76b3903d 1511/* This only works on NTFS volumes, but is useful to have. */
480b0c5b 1512int
76b3903d 1513sys_link (const char * old, const char * new)
480b0c5b 1514{
76b3903d
GV
1515 HANDLE fileh;
1516 int result = -1;
1517 char oldname[MAX_PATH], newname[MAX_PATH];
1518
1519 if (old == NULL || new == NULL)
1520 {
1521 errno = ENOENT;
1522 return -1;
1523 }
1524
1525 strcpy (oldname, map_w32_filename (old, NULL));
1526 strcpy (newname, map_w32_filename (new, NULL));
1527
1528 fileh = CreateFile (oldname, 0, 0, NULL, OPEN_EXISTING,
1529 FILE_FLAG_BACKUP_SEMANTICS, NULL);
1530 if (fileh != INVALID_HANDLE_VALUE)
1531 {
1532 int wlen;
1533
1534 /* Confusingly, the "alternate" stream name field does not apply
1535 when restoring a hard link, and instead contains the actual
1536 stream data for the link (ie. the name of the link to create).
1537 The WIN32_STREAM_ID structure before the cStreamName field is
1538 the stream header, which is then immediately followed by the
1539 stream data. */
1540
1541 struct {
1542 WIN32_STREAM_ID wid;
1543 WCHAR wbuffer[MAX_PATH]; /* extra space for link name */
1544 } data;
1545
1546 wlen = MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, newname, -1,
1547 data.wid.cStreamName, MAX_PATH);
1548 if (wlen > 0)
1549 {
1550 LPVOID context = NULL;
1551 DWORD wbytes = 0;
1552
1553 data.wid.dwStreamId = BACKUP_LINK;
1554 data.wid.dwStreamAttributes = 0;
1555 data.wid.Size.LowPart = wlen * sizeof(WCHAR);
1556 data.wid.Size.HighPart = 0;
1557 data.wid.dwStreamNameSize = 0;
1558
1559 if (BackupWrite (fileh, (LPBYTE)&data,
1560 offsetof (WIN32_STREAM_ID, cStreamName)
1561 + data.wid.Size.LowPart,
1562 &wbytes, FALSE, FALSE, &context)
1563 && BackupWrite (fileh, NULL, 0, &wbytes, TRUE, FALSE, &context))
1564 {
1565 /* succeeded */
1566 result = 0;
1567 }
1568 else
1569 {
1570 /* Should try mapping GetLastError to errno; for now just
1571 indicate a general error (eg. links not supported). */
1572 errno = EINVAL; // perhaps EMLINK?
1573 }
1574 }
1575
1576 CloseHandle (fileh);
1577 }
1578 else
1579 errno = ENOENT;
1580
1581 return result;
480b0c5b
GV
1582}
1583
1584int
1585sys_mkdir (const char * path)
1586{
fbd6baed 1587 return _mkdir (map_w32_filename (path, NULL));
480b0c5b
GV
1588}
1589
9d1778b1
RS
1590/* Because of long name mapping issues, we need to implement this
1591 ourselves. Also, MSVC's _mktemp returns NULL when it can't generate
1592 a unique name, instead of setting the input template to an empty
1593 string.
1594
1595 Standard algorithm seems to be use pid or tid with a letter on the
1596 front (in place of the 6 X's) and cycle through the letters to find a
1597 unique name. We extend that to allow any reasonable character as the
1598 first of the 6 X's. */
480b0c5b
GV
1599char *
1600sys_mktemp (char * template)
1601{
9d1778b1
RS
1602 char * p;
1603 int i;
1604 unsigned uid = GetCurrentThreadId ();
1605 static char first_char[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
1606
1607 if (template == NULL)
1608 return NULL;
1609 p = template + strlen (template);
1610 i = 5;
1611 /* replace up to the last 5 X's with uid in decimal */
1612 while (--p >= template && p[0] == 'X' && --i >= 0)
1613 {
1614 p[0] = '0' + uid % 10;
1615 uid /= 10;
1616 }
1617
1618 if (i < 0 && p[0] == 'X')
1619 {
1620 i = 0;
1621 do
1622 {
1623 int save_errno = errno;
1624 p[0] = first_char[i];
1625 if (sys_access (template, 0) < 0)
1626 {
1627 errno = save_errno;
1628 return template;
1629 }
1630 }
1631 while (++i < sizeof (first_char));
1632 }
1633
1634 /* Template is badly formed or else we can't generate a unique name,
1635 so return empty string */
1636 template[0] = 0;
1637 return template;
480b0c5b
GV
1638}
1639
1640int
1641sys_open (const char * path, int oflag, int mode)
1642{
1643 /* Force all file handles to be non-inheritable. */
fbd6baed 1644 return _open (map_w32_filename (path, NULL), oflag | _O_NOINHERIT, mode);
480b0c5b
GV
1645}
1646
1647int
1648sys_rename (const char * oldname, const char * newname)
1649{
eb9ea53f 1650 int result;
b3308d2e 1651 char temp[MAX_PATH];
480b0c5b 1652
e9e23e23 1653 /* MoveFile on Windows 95 doesn't correctly change the short file name
5162ffce
MB
1654 alias in a number of circumstances (it is not easy to predict when
1655 just by looking at oldname and newname, unfortunately). In these
1656 cases, renaming through a temporary name avoids the problem.
1657
e9e23e23 1658 A second problem on Windows 95 is that renaming through a temp name when
5162ffce
MB
1659 newname is uppercase fails (the final long name ends up in
1660 lowercase, although the short alias might be uppercase) UNLESS the
1661 long temp name is not 8.3.
1662
e9e23e23 1663 So, on Windows 95 we always rename through a temp name, and we make sure
5162ffce 1664 the temp name has a long extension to ensure correct renaming. */
480b0c5b 1665
fbd6baed 1666 strcpy (temp, map_w32_filename (oldname, NULL));
480b0c5b 1667
76b3903d 1668 if (os_subtype == OS_WIN95)
480b0c5b 1669 {
b3308d2e 1670 char * o;
480b0c5b 1671 char * p;
b3308d2e
KH
1672 int i = 0;
1673
1674 oldname = map_w32_filename (oldname, NULL);
1675 if (o = strrchr (oldname, '\\'))
1676 o++;
1677 else
1678 o = (char *) oldname;
480b0c5b 1679
480b0c5b
GV
1680 if (p = strrchr (temp, '\\'))
1681 p++;
1682 else
1683 p = temp;
b3308d2e
KH
1684
1685 do
1686 {
1687 /* Force temp name to require a manufactured 8.3 alias - this
1688 seems to make the second rename work properly. */
f313ee82 1689 sprintf (p, "_.%s.%u", o, i);
b3308d2e 1690 i++;
58f0cb7e 1691 result = rename (oldname, temp);
b3308d2e
KH
1692 }
1693 /* This loop must surely terminate! */
f313ee82 1694 while (result < 0 && (errno == EEXIST || errno == EACCES));
58f0cb7e 1695 if (result < 0)
480b0c5b
GV
1696 return -1;
1697 }
1698
1699 /* Emulate Unix behaviour - newname is deleted if it already exists
5162ffce 1700 (at least if it is a file; don't do this for directories).
76b3903d 1701
b3308d2e
KH
1702 Since we mustn't do this if we are just changing the case of the
1703 file name (we would end up deleting the file we are trying to
1704 rename!), we let rename detect if the destination file already
1705 exists - that way we avoid the possible pitfalls of trying to
1706 determine ourselves whether two names really refer to the same
1707 file, which is not always possible in the general case. (Consider
1708 all the permutations of shared or subst'd drives, etc.) */
1709
1710 newname = map_w32_filename (newname, NULL);
eb9ea53f 1711 result = rename (temp, newname);
b3308d2e
KH
1712
1713 if (result < 0
f313ee82 1714 && (errno == EEXIST || errno == EACCES)
b3308d2e
KH
1715 && _chmod (newname, 0666) == 0
1716 && _unlink (newname) == 0)
1717 result = rename (temp, newname);
480b0c5b 1718
eb9ea53f 1719 return result;
480b0c5b
GV
1720}
1721
1722int
1723sys_rmdir (const char * path)
1724{
fbd6baed 1725 return _rmdir (map_w32_filename (path, NULL));
480b0c5b
GV
1726}
1727
1728int
1729sys_unlink (const char * path)
1730{
16bb7578
GV
1731 path = map_w32_filename (path, NULL);
1732
1733 /* On Unix, unlink works without write permission. */
1734 _chmod (path, 0666);
1735 return _unlink (path);
480b0c5b
GV
1736}
1737
1738static FILETIME utc_base_ft;
1739static long double utc_base;
1740static int init = 0;
1741
1742static time_t
1743convert_time (FILETIME ft)
1744{
1745 long double ret;
1746
1747 if (!init)
1748 {
1749 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
1750 SYSTEMTIME st;
1751
1752 st.wYear = 1970;
1753 st.wMonth = 1;
1754 st.wDay = 1;
1755 st.wHour = 0;
1756 st.wMinute = 0;
1757 st.wSecond = 0;
1758 st.wMilliseconds = 0;
1759
1760 SystemTimeToFileTime (&st, &utc_base_ft);
1761 utc_base = (long double) utc_base_ft.dwHighDateTime
1762 * 4096 * 1024 * 1024 + utc_base_ft.dwLowDateTime;
1763 init = 1;
1764 }
1765
1766 if (CompareFileTime (&ft, &utc_base_ft) < 0)
1767 return 0;
1768
1769 ret = (long double) ft.dwHighDateTime * 4096 * 1024 * 1024 + ft.dwLowDateTime;
1770 ret -= utc_base;
1771 return (time_t) (ret * 1e-7);
1772}
1773
480b0c5b
GV
1774void
1775convert_from_time_t (time_t time, FILETIME * pft)
1776{
1777 long double tmp;
1778
1779 if (!init)
1780 {
1781 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
1782 SYSTEMTIME st;
1783
1784 st.wYear = 1970;
1785 st.wMonth = 1;
1786 st.wDay = 1;
1787 st.wHour = 0;
1788 st.wMinute = 0;
1789 st.wSecond = 0;
1790 st.wMilliseconds = 0;
1791
1792 SystemTimeToFileTime (&st, &utc_base_ft);
1793 utc_base = (long double) utc_base_ft.dwHighDateTime
1794 * 4096 * 1024 * 1024 + utc_base_ft.dwLowDateTime;
1795 init = 1;
1796 }
1797
1798 /* time in 100ns units since 1-Jan-1601 */
1799 tmp = (long double) time * 1e7 + utc_base;
1800 pft->dwHighDateTime = (DWORD) (tmp / (4096.0 * 1024 * 1024));
16bb7578 1801 pft->dwLowDateTime = (DWORD) (tmp - (4096.0 * 1024 * 1024) * pft->dwHighDateTime);
480b0c5b 1802}
480b0c5b 1803
76b3903d
GV
1804#if 0
1805/* No reason to keep this; faking inode values either by hashing or even
1806 using the file index from GetInformationByHandle, is not perfect and
1807 so by default Emacs doesn't use the inode values on Windows.
1808 Instead, we now determine file-truename correctly (except for
1809 possible drive aliasing etc). */
1810
1811/* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
480b0c5b 1812static unsigned
76b3903d 1813hashval (const unsigned char * str)
480b0c5b
GV
1814{
1815 unsigned h = 0;
480b0c5b
GV
1816 while (*str)
1817 {
1818 h = (h << 4) + *str++;
76b3903d 1819 h ^= (h >> 28);
480b0c5b
GV
1820 }
1821 return h;
1822}
1823
1824/* Return the hash value of the canonical pathname, excluding the
1825 drive/UNC header, to get a hopefully unique inode number. */
76b3903d 1826static DWORD
480b0c5b
GV
1827generate_inode_val (const char * name)
1828{
1829 char fullname[ MAX_PATH ];
1830 char * p;
1831 unsigned hash;
1832
76b3903d
GV
1833 /* Get the truly canonical filename, if it exists. (Note: this
1834 doesn't resolve aliasing due to subst commands, or recognise hard
1835 links. */
1836 if (!w32_get_long_filename ((char *)name, fullname, MAX_PATH))
1837 abort ();
1838
1839 parse_root (fullname, &p);
fbd6baed 1840 /* Normal W32 filesystems are still case insensitive. */
480b0c5b 1841 _strlwr (p);
76b3903d 1842 return hashval (p);
480b0c5b
GV
1843}
1844
76b3903d
GV
1845#endif
1846
480b0c5b
GV
1847/* MSVC stat function can't cope with UNC names and has other bugs, so
1848 replace it with our own. This also allows us to calculate consistent
1849 inode values without hacks in the main Emacs code. */
1850int
1851stat (const char * path, struct stat * buf)
1852{
eb9ea53f 1853 char *name, *r;
480b0c5b
GV
1854 WIN32_FIND_DATA wfd;
1855 HANDLE fh;
76b3903d 1856 DWORD fake_inode;
480b0c5b
GV
1857 int permission;
1858 int len;
1859 int rootdir = FALSE;
1860
1861 if (path == NULL || buf == NULL)
1862 {
1863 errno = EFAULT;
1864 return -1;
1865 }
1866
fbd6baed 1867 name = (char *) map_w32_filename (path, &path);
bb1584c8
RS
1868 /* must be valid filename, no wild cards or other illegal characters */
1869 if (strpbrk (name, "*?|<>\""))
480b0c5b
GV
1870 {
1871 errno = ENOENT;
1872 return -1;
1873 }
1874
eb9ea53f
GV
1875 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
1876 r = IS_DEVICE_SEP (name[1]) ? &name[2] : name;
1877 if (IS_DIRECTORY_SEP (r[0]) && r[1] == '.' && r[2] == '.' && r[3] == '\0')
1878 {
1879 r[1] = r[2] = '\0';
1880 }
1881
480b0c5b
GV
1882 /* Remove trailing directory separator, unless name is the root
1883 directory of a drive or UNC volume in which case ensure there
1884 is a trailing separator. */
1885 len = strlen (name);
1886 rootdir = (path >= name + len - 1
1887 && (IS_DIRECTORY_SEP (*path) || *path == 0));
1888 name = strcpy (alloca (len + 2), name);
1889
9d3355d1
GV
1890 if (is_unc_volume (name))
1891 {
1892 DWORD attrs = unc_volume_file_attributes (name);
1893
1894 if (attrs == -1)
1895 return -1;
1896
1897 memset (&wfd, 0, sizeof (wfd));
1898 wfd.dwFileAttributes = attrs;
1899 wfd.ftCreationTime = utc_base_ft;
1900 wfd.ftLastAccessTime = utc_base_ft;
1901 wfd.ftLastWriteTime = utc_base_ft;
1902 strcpy (wfd.cFileName, name);
1903 }
1904 else if (rootdir)
480b0c5b
GV
1905 {
1906 if (!IS_DIRECTORY_SEP (name[len-1]))
1907 strcat (name, "\\");
1908 if (GetDriveType (name) < 2)
1909 {
1910 errno = ENOENT;
1911 return -1;
1912 }
1913 memset (&wfd, 0, sizeof (wfd));
1914 wfd.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
1915 wfd.ftCreationTime = utc_base_ft;
1916 wfd.ftLastAccessTime = utc_base_ft;
1917 wfd.ftLastWriteTime = utc_base_ft;
1918 strcpy (wfd.cFileName, name);
1919 }
1920 else
1921 {
1922 if (IS_DIRECTORY_SEP (name[len-1]))
1923 name[len - 1] = 0;
76b3903d
GV
1924
1925 /* (This is hacky, but helps when doing file completions on
1926 network drives.) Optimize by using information available from
1927 active readdir if possible. */
1928 if (dir_find_handle != INVALID_HANDLE_VALUE
1929 && (len = strlen (dir_pathname)),
1930 strnicmp (name, dir_pathname, len) == 0
1931 && IS_DIRECTORY_SEP (name[len])
1932 && stricmp (name + len + 1, dir_static.d_name) == 0)
480b0c5b 1933 {
76b3903d
GV
1934 /* This was the last entry returned by readdir. */
1935 wfd = dir_find_data;
1936 }
1937 else
1938 {
1939 fh = FindFirstFile (name, &wfd);
1940 if (fh == INVALID_HANDLE_VALUE)
1941 {
1942 errno = ENOENT;
1943 return -1;
1944 }
1945 FindClose (fh);
480b0c5b 1946 }
480b0c5b
GV
1947 }
1948
1949 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1950 {
1951 buf->st_mode = _S_IFDIR;
1952 buf->st_nlink = 2; /* doesn't really matter */
76b3903d 1953 fake_inode = 0; /* this doesn't either I think */
480b0c5b 1954 }
710ea1b8
RS
1955 else if (!NILP (Vw32_get_true_file_attributes)
1956 /* No access rights required to get info. */
1957 && (fh = CreateFile (name, 0, 0, NULL, OPEN_EXISTING, 0, NULL))
1958 != INVALID_HANDLE_VALUE)
480b0c5b 1959 {
480b0c5b
GV
1960 /* This is more accurate in terms of gettting the correct number
1961 of links, but is quite slow (it is noticable when Emacs is
1962 making a list of file name completions). */
1963 BY_HANDLE_FILE_INFORMATION info;
1964
480b0c5b
GV
1965 if (GetFileInformationByHandle (fh, &info))
1966 {
480b0c5b 1967 buf->st_nlink = info.nNumberOfLinks;
76b3903d
GV
1968 /* Might as well use file index to fake inode values, but this
1969 is not guaranteed to be unique unless we keep a handle open
1970 all the time (even then there are situations where it is
1971 not unique). Reputedly, there are at most 48 bits of info
1972 (on NTFS, presumably less on FAT). */
1973 fake_inode = info.nFileIndexLow ^ info.nFileIndexHigh;
480b0c5b
GV
1974 }
1975 else
1976 {
01f31dfb
AI
1977 buf->st_nlink = 1;
1978 fake_inode = 0;
1979 }
1980
1981 switch (GetFileType (fh))
1982 {
1983 case FILE_TYPE_DISK:
1984 buf->st_mode = _S_IFREG;
1985 break;
1986 case FILE_TYPE_PIPE:
1987 buf->st_mode = _S_IFIFO;
1988 break;
1989 case FILE_TYPE_CHAR:
1990 case FILE_TYPE_UNKNOWN:
1991 default:
1992 buf->st_mode = _S_IFCHR;
480b0c5b 1993 }
01f31dfb 1994 CloseHandle (fh);
76b3903d
GV
1995 }
1996 else
1997 {
1998 /* Don't bother to make this information more accurate. */
480b0c5b
GV
1999 buf->st_mode = _S_IFREG;
2000 buf->st_nlink = 1;
76b3903d
GV
2001 fake_inode = 0;
2002 }
2003
2004#if 0
2005 /* Not sure if there is any point in this. */
2006 if (!NILP (Vw32_generate_fake_inodes))
2007 fake_inode = generate_inode_val (name);
2008 else if (fake_inode == 0)
2009 {
2010 /* For want of something better, try to make everything unique. */
2011 static DWORD gen_num = 0;
2012 fake_inode = ++gen_num;
480b0c5b 2013 }
76b3903d
GV
2014#endif
2015
2016 /* MSVC defines _ino_t to be short; other libc's might not. */
2017 if (sizeof (buf->st_ino) == 2)
2018 buf->st_ino = fake_inode ^ (fake_inode >> 16);
2019 else
2020 buf->st_ino = fake_inode;
480b0c5b
GV
2021
2022 /* consider files to belong to current user */
2023 buf->st_uid = the_passwd.pw_uid;
2024 buf->st_gid = the_passwd.pw_gid;
2025
fbd6baed 2026 /* volume_info is set indirectly by map_w32_filename */
480b0c5b
GV
2027 buf->st_dev = volume_info.serialnum;
2028 buf->st_rdev = volume_info.serialnum;
2029
480b0c5b
GV
2030
2031 buf->st_size = wfd.nFileSizeLow;
2032
2033 /* Convert timestamps to Unix format. */
2034 buf->st_mtime = convert_time (wfd.ftLastWriteTime);
2035 buf->st_atime = convert_time (wfd.ftLastAccessTime);
2036 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
2037 buf->st_ctime = convert_time (wfd.ftCreationTime);
2038 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
2039
2040 /* determine rwx permissions */
2041 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
2042 permission = _S_IREAD;
2043 else
2044 permission = _S_IREAD | _S_IWRITE;
2045
2046 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
2047 permission |= _S_IEXEC;
b3308d2e
KH
2048 else if (is_exec (name))
2049 permission |= _S_IEXEC;
480b0c5b
GV
2050
2051 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
2052
2053 return 0;
2054}
2055
16bb7578
GV
2056/* Provide fstat and utime as well as stat for consistent handling of
2057 file timestamps. */
2058int
2059fstat (int desc, struct stat * buf)
2060{
2061 HANDLE fh = (HANDLE) _get_osfhandle (desc);
2062 BY_HANDLE_FILE_INFORMATION info;
2063 DWORD fake_inode;
2064 int permission;
2065
2066 switch (GetFileType (fh) & ~FILE_TYPE_REMOTE)
2067 {
2068 case FILE_TYPE_DISK:
2069 buf->st_mode = _S_IFREG;
2070 if (!GetFileInformationByHandle (fh, &info))
2071 {
2072 errno = EACCES;
2073 return -1;
2074 }
2075 break;
2076 case FILE_TYPE_PIPE:
2077 buf->st_mode = _S_IFIFO;
2078 goto non_disk;
2079 case FILE_TYPE_CHAR:
2080 case FILE_TYPE_UNKNOWN:
2081 default:
2082 buf->st_mode = _S_IFCHR;
2083 non_disk:
2084 memset (&info, 0, sizeof (info));
2085 info.dwFileAttributes = 0;
2086 info.ftCreationTime = utc_base_ft;
2087 info.ftLastAccessTime = utc_base_ft;
2088 info.ftLastWriteTime = utc_base_ft;
2089 }
2090
2091 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
2092 {
2093 buf->st_mode = _S_IFDIR;
2094 buf->st_nlink = 2; /* doesn't really matter */
2095 fake_inode = 0; /* this doesn't either I think */
2096 }
2097 else
2098 {
2099 buf->st_nlink = info.nNumberOfLinks;
2100 /* Might as well use file index to fake inode values, but this
2101 is not guaranteed to be unique unless we keep a handle open
2102 all the time (even then there are situations where it is
2103 not unique). Reputedly, there are at most 48 bits of info
2104 (on NTFS, presumably less on FAT). */
2105 fake_inode = info.nFileIndexLow ^ info.nFileIndexHigh;
2106 }
2107
2108 /* MSVC defines _ino_t to be short; other libc's might not. */
2109 if (sizeof (buf->st_ino) == 2)
2110 buf->st_ino = fake_inode ^ (fake_inode >> 16);
2111 else
2112 buf->st_ino = fake_inode;
2113
2114 /* consider files to belong to current user */
2115 buf->st_uid = 0;
2116 buf->st_gid = 0;
2117
2118 buf->st_dev = info.dwVolumeSerialNumber;
2119 buf->st_rdev = info.dwVolumeSerialNumber;
2120
2121 buf->st_size = info.nFileSizeLow;
2122
2123 /* Convert timestamps to Unix format. */
2124 buf->st_mtime = convert_time (info.ftLastWriteTime);
2125 buf->st_atime = convert_time (info.ftLastAccessTime);
2126 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
2127 buf->st_ctime = convert_time (info.ftCreationTime);
2128 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
2129
2130 /* determine rwx permissions */
2131 if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
2132 permission = _S_IREAD;
2133 else
2134 permission = _S_IREAD | _S_IWRITE;
2135
2136 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
2137 permission |= _S_IEXEC;
2138 else
2139 {
2140#if 0 /* no way of knowing the filename */
2141 char * p = strrchr (name, '.');
2142 if (p != NULL &&
2143 (stricmp (p, ".exe") == 0 ||
2144 stricmp (p, ".com") == 0 ||
2145 stricmp (p, ".bat") == 0 ||
2146 stricmp (p, ".cmd") == 0))
2147 permission |= _S_IEXEC;
2148#endif
2149 }
2150
2151 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
2152
2153 return 0;
2154}
2155
2156int
2157utime (const char *name, struct utimbuf *times)
2158{
2159 struct utimbuf deftime;
2160 HANDLE fh;
2161 FILETIME mtime;
2162 FILETIME atime;
2163
2164 if (times == NULL)
2165 {
2166 deftime.modtime = deftime.actime = time (NULL);
2167 times = &deftime;
2168 }
2169
2170 /* Need write access to set times. */
2171 fh = CreateFile (name, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
2172 0, OPEN_EXISTING, 0, NULL);
2173 if (fh)
2174 {
2175 convert_from_time_t (times->actime, &atime);
2176 convert_from_time_t (times->modtime, &mtime);
2177 if (!SetFileTime (fh, NULL, &atime, &mtime))
2178 {
2179 CloseHandle (fh);
2180 errno = EACCES;
2181 return -1;
2182 }
2183 CloseHandle (fh);
2184 }
2185 else
2186 {
2187 errno = EINVAL;
2188 return -1;
2189 }
2190 return 0;
2191}
2192
480b0c5b
GV
2193#ifdef HAVE_SOCKETS
2194
2195/* Wrappers for winsock functions to map between our file descriptors
2196 and winsock's handles; also set h_errno for convenience.
2197
2198 To allow Emacs to run on systems which don't have winsock support
2199 installed, we dynamically link to winsock on startup if present, and
2200 otherwise provide the minimum necessary functionality
2201 (eg. gethostname). */
2202
2203/* function pointers for relevant socket functions */
2204int (PASCAL *pfn_WSAStartup) (WORD wVersionRequired, LPWSADATA lpWSAData);
2205void (PASCAL *pfn_WSASetLastError) (int iError);
2206int (PASCAL *pfn_WSAGetLastError) (void);
2207int (PASCAL *pfn_socket) (int af, int type, int protocol);
2208int (PASCAL *pfn_bind) (SOCKET s, const struct sockaddr *addr, int namelen);
2209int (PASCAL *pfn_connect) (SOCKET s, const struct sockaddr *addr, int namelen);
2210int (PASCAL *pfn_ioctlsocket) (SOCKET s, long cmd, u_long *argp);
2211int (PASCAL *pfn_recv) (SOCKET s, char * buf, int len, int flags);
2212int (PASCAL *pfn_send) (SOCKET s, const char * buf, int len, int flags);
2213int (PASCAL *pfn_closesocket) (SOCKET s);
2214int (PASCAL *pfn_shutdown) (SOCKET s, int how);
2215int (PASCAL *pfn_WSACleanup) (void);
2216
2217u_short (PASCAL *pfn_htons) (u_short hostshort);
2218u_short (PASCAL *pfn_ntohs) (u_short netshort);
2219unsigned long (PASCAL *pfn_inet_addr) (const char * cp);
2220int (PASCAL *pfn_gethostname) (char * name, int namelen);
2221struct hostent * (PASCAL *pfn_gethostbyname) (const char * name);
2222struct servent * (PASCAL *pfn_getservbyname) (const char * name, const char * proto);
f1614061
RS
2223
2224/* SetHandleInformation is only needed to make sockets non-inheritable. */
2225BOOL (WINAPI *pfn_SetHandleInformation) (HANDLE object, DWORD mask, DWORD flags);
2226#ifndef HANDLE_FLAG_INHERIT
2227#define HANDLE_FLAG_INHERIT 1
2228#endif
480b0c5b 2229
f249a012
RS
2230HANDLE winsock_lib;
2231static int winsock_inuse;
480b0c5b 2232
f249a012 2233BOOL
480b0c5b
GV
2234term_winsock (void)
2235{
f249a012 2236 if (winsock_lib != NULL && winsock_inuse == 0)
480b0c5b 2237 {
f249a012
RS
2238 /* Not sure what would cause WSAENETDOWN, or even if it can happen
2239 after WSAStartup returns successfully, but it seems reasonable
2240 to allow unloading winsock anyway in that case. */
2241 if (pfn_WSACleanup () == 0 ||
2242 pfn_WSAGetLastError () == WSAENETDOWN)
2243 {
2244 if (FreeLibrary (winsock_lib))
2245 winsock_lib = NULL;
2246 return TRUE;
2247 }
480b0c5b 2248 }
f249a012 2249 return FALSE;
480b0c5b
GV
2250}
2251
f249a012
RS
2252BOOL
2253init_winsock (int load_now)
480b0c5b
GV
2254{
2255 WSADATA winsockData;
2256
f249a012
RS
2257 if (winsock_lib != NULL)
2258 return TRUE;
f1614061
RS
2259
2260 pfn_SetHandleInformation = NULL;
2261 pfn_SetHandleInformation
2262 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
2263 "SetHandleInformation");
2264
480b0c5b
GV
2265 winsock_lib = LoadLibrary ("wsock32.dll");
2266
2267 if (winsock_lib != NULL)
2268 {
2269 /* dynamically link to socket functions */
2270
2271#define LOAD_PROC(fn) \
2272 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
2273 goto fail;
2274
2275 LOAD_PROC( WSAStartup );
2276 LOAD_PROC( WSASetLastError );
2277 LOAD_PROC( WSAGetLastError );
2278 LOAD_PROC( socket );
2279 LOAD_PROC( bind );
2280 LOAD_PROC( connect );
2281 LOAD_PROC( ioctlsocket );
2282 LOAD_PROC( recv );
2283 LOAD_PROC( send );
2284 LOAD_PROC( closesocket );
2285 LOAD_PROC( shutdown );
2286 LOAD_PROC( htons );
2287 LOAD_PROC( ntohs );
2288 LOAD_PROC( inet_addr );
2289 LOAD_PROC( gethostname );
2290 LOAD_PROC( gethostbyname );
2291 LOAD_PROC( getservbyname );
2292 LOAD_PROC( WSACleanup );
2293
f249a012
RS
2294#undef LOAD_PROC
2295
480b0c5b
GV
2296 /* specify version 1.1 of winsock */
2297 if (pfn_WSAStartup (0x101, &winsockData) == 0)
2298 {
f249a012
RS
2299 if (winsockData.wVersion != 0x101)
2300 goto fail;
2301
2302 if (!load_now)
2303 {
2304 /* Report that winsock exists and is usable, but leave
2305 socket functions disabled. I am assuming that calling
2306 WSAStartup does not require any network interaction,
2307 and in particular does not cause or require a dial-up
2308 connection to be established. */
2309
2310 pfn_WSACleanup ();
2311 FreeLibrary (winsock_lib);
2312 winsock_lib = NULL;
2313 }
2314 winsock_inuse = 0;
2315 return TRUE;
480b0c5b
GV
2316 }
2317
2318 fail:
2319 FreeLibrary (winsock_lib);
f249a012 2320 winsock_lib = NULL;
480b0c5b 2321 }
f249a012
RS
2322
2323 return FALSE;
480b0c5b
GV
2324}
2325
2326
2327int h_errno = 0;
2328
2329/* function to set h_errno for compatability; map winsock error codes to
2330 normal system codes where they overlap (non-overlapping definitions
2331 are already in <sys/socket.h> */
2332static void set_errno ()
2333{
f249a012 2334 if (winsock_lib == NULL)
480b0c5b
GV
2335 h_errno = EINVAL;
2336 else
2337 h_errno = pfn_WSAGetLastError ();
2338
2339 switch (h_errno)
2340 {
2341 case WSAEACCES: h_errno = EACCES; break;
2342 case WSAEBADF: h_errno = EBADF; break;
2343 case WSAEFAULT: h_errno = EFAULT; break;
2344 case WSAEINTR: h_errno = EINTR; break;
2345 case WSAEINVAL: h_errno = EINVAL; break;
2346 case WSAEMFILE: h_errno = EMFILE; break;
2347 case WSAENAMETOOLONG: h_errno = ENAMETOOLONG; break;
2348 case WSAENOTEMPTY: h_errno = ENOTEMPTY; break;
2349 }
2350 errno = h_errno;
2351}
2352
2353static void check_errno ()
2354{
f249a012 2355 if (h_errno == 0 && winsock_lib != NULL)
480b0c5b
GV
2356 pfn_WSASetLastError (0);
2357}
2358
2359/* [andrewi 3-May-96] I've had conflicting results using both methods,
2360 but I believe the method of keeping the socket handle separate (and
2361 insuring it is not inheritable) is the correct one. */
2362
2363//#define SOCK_REPLACE_HANDLE
2364
2365#ifdef SOCK_REPLACE_HANDLE
2366#define SOCK_HANDLE(fd) ((SOCKET) _get_osfhandle (fd))
2367#else
2368#define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
2369#endif
2370
2371int
2372sys_socket(int af, int type, int protocol)
2373{
2374 int fd;
2375 long s;
2376 child_process * cp;
2377
f249a012 2378 if (winsock_lib == NULL)
480b0c5b
GV
2379 {
2380 h_errno = ENETDOWN;
2381 return INVALID_SOCKET;
2382 }
2383
2384 check_errno ();
2385
2386 /* call the real socket function */
2387 s = (long) pfn_socket (af, type, protocol);
2388
2389 if (s != INVALID_SOCKET)
2390 {
2391 /* Although under NT 3.5 _open_osfhandle will accept a socket
2392 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
2393 that does not work under NT 3.1. However, we can get the same
2394 effect by using a backdoor function to replace an existing
2395 descriptor handle with the one we want. */
2396
2397 /* allocate a file descriptor (with appropriate flags) */
2398 fd = _open ("NUL:", _O_RDWR);
2399 if (fd >= 0)
2400 {
2401#ifdef SOCK_REPLACE_HANDLE
2402 /* now replace handle to NUL with our socket handle */
2403 CloseHandle ((HANDLE) _get_osfhandle (fd));
2404 _free_osfhnd (fd);
2405 _set_osfhnd (fd, s);
2406 /* setmode (fd, _O_BINARY); */
2407#else
2408 /* Make a non-inheritable copy of the socket handle. */
2409 {
2410 HANDLE parent;
2411 HANDLE new_s = INVALID_HANDLE_VALUE;
2412
2413 parent = GetCurrentProcess ();
2414
f1614061
RS
2415 /* Apparently there is a bug in NT 3.51 with some service
2416 packs, which prevents using DuplicateHandle to make a
2417 socket handle non-inheritable (causes WSACleanup to
2418 hang). The work-around is to use SetHandleInformation
2419 instead if it is available and implemented. */
2420 if (!pfn_SetHandleInformation
2421 || !pfn_SetHandleInformation ((HANDLE) s,
2422 HANDLE_FLAG_INHERIT,
caf1a172 2423 0))
f1614061
RS
2424 {
2425 DuplicateHandle (parent,
2426 (HANDLE) s,
2427 parent,
2428 &new_s,
2429 0,
2430 FALSE,
2431 DUPLICATE_SAME_ACCESS);
2432 pfn_closesocket (s);
2433 s = (SOCKET) new_s;
2434 }
2435 fd_info[fd].hnd = (HANDLE) s;
480b0c5b
GV
2436 }
2437#endif
2438
2439 /* set our own internal flags */
2440 fd_info[fd].flags = FILE_SOCKET | FILE_BINARY | FILE_READ | FILE_WRITE;
2441
2442 cp = new_child ();
2443 if (cp)
2444 {
2445 cp->fd = fd;
2446 cp->status = STATUS_READ_ACKNOWLEDGED;
2447
2448 /* attach child_process to fd_info */
2449 if (fd_info[ fd ].cp != NULL)
2450 {
2451 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd));
2452 abort ();
2453 }
2454
2455 fd_info[ fd ].cp = cp;
2456
2457 /* success! */
f249a012 2458 winsock_inuse++; /* count open sockets */
480b0c5b
GV
2459 return fd;
2460 }
2461
2462 /* clean up */
2463 _close (fd);
2464 }
2465 pfn_closesocket (s);
2466 h_errno = EMFILE;
2467 }
2468 set_errno ();
2469
2470 return -1;
2471}
2472
2473
2474int
2475sys_bind (int s, const struct sockaddr * addr, int namelen)
2476{
f249a012 2477 if (winsock_lib == NULL)
480b0c5b
GV
2478 {
2479 h_errno = ENOTSOCK;
2480 return SOCKET_ERROR;
2481 }
2482
2483 check_errno ();
2484 if (fd_info[s].flags & FILE_SOCKET)
2485 {
2486 int rc = pfn_bind (SOCK_HANDLE (s), addr, namelen);
2487 if (rc == SOCKET_ERROR)
2488 set_errno ();
2489 return rc;
2490 }
2491 h_errno = ENOTSOCK;
2492 return SOCKET_ERROR;
2493}
2494
2495
2496int
2497sys_connect (int s, const struct sockaddr * name, int namelen)
2498{
f249a012 2499 if (winsock_lib == NULL)
480b0c5b
GV
2500 {
2501 h_errno = ENOTSOCK;
2502 return SOCKET_ERROR;
2503 }
2504
2505 check_errno ();
2506 if (fd_info[s].flags & FILE_SOCKET)
2507 {
2508 int rc = pfn_connect (SOCK_HANDLE (s), name, namelen);
2509 if (rc == SOCKET_ERROR)
2510 set_errno ();
2511 return rc;
2512 }
2513 h_errno = ENOTSOCK;
2514 return SOCKET_ERROR;
2515}
2516
2517u_short
2518sys_htons (u_short hostshort)
2519{
f249a012 2520 return (winsock_lib != NULL) ?
480b0c5b
GV
2521 pfn_htons (hostshort) : hostshort;
2522}
2523
2524u_short
2525sys_ntohs (u_short netshort)
2526{
f249a012 2527 return (winsock_lib != NULL) ?
480b0c5b
GV
2528 pfn_ntohs (netshort) : netshort;
2529}
2530
2531unsigned long
2532sys_inet_addr (const char * cp)
2533{
f249a012 2534 return (winsock_lib != NULL) ?
480b0c5b
GV
2535 pfn_inet_addr (cp) : INADDR_NONE;
2536}
2537
2538int
2539sys_gethostname (char * name, int namelen)
2540{
f249a012 2541 if (winsock_lib != NULL)
480b0c5b
GV
2542 return pfn_gethostname (name, namelen);
2543
2544 if (namelen > MAX_COMPUTERNAME_LENGTH)
2545 return !GetComputerName (name, &namelen);
2546
2547 h_errno = EFAULT;
2548 return SOCKET_ERROR;
2549}
2550
2551struct hostent *
2552sys_gethostbyname(const char * name)
2553{
2554 struct hostent * host;
2555
f249a012 2556 if (winsock_lib == NULL)
480b0c5b
GV
2557 {
2558 h_errno = ENETDOWN;
2559 return NULL;
2560 }
2561
2562 check_errno ();
2563 host = pfn_gethostbyname (name);
2564 if (!host)
2565 set_errno ();
2566 return host;
2567}
2568
2569struct servent *
2570sys_getservbyname(const char * name, const char * proto)
2571{
2572 struct servent * serv;
2573
f249a012 2574 if (winsock_lib == NULL)
480b0c5b
GV
2575 {
2576 h_errno = ENETDOWN;
2577 return NULL;
2578 }
2579
2580 check_errno ();
2581 serv = pfn_getservbyname (name, proto);
2582 if (!serv)
2583 set_errno ();
2584 return serv;
2585}
2586
380961a6
GV
2587int
2588sys_shutdown (int s, int how)
2589{
2590 int rc;
2591
2592 if (winsock_lib == NULL)
2593 {
2594 h_errno = ENETDOWN;
2595 return SOCKET_ERROR;
2596 }
2597
2598 check_errno ();
2599 if (fd_info[s].flags & FILE_SOCKET)
2600 {
2601 int rc = pfn_shutdown (SOCK_HANDLE (s), how);
2602 if (rc == SOCKET_ERROR)
2603 set_errno ();
2604 return rc;
2605 }
2606 h_errno = ENOTSOCK;
2607 return SOCKET_ERROR;
2608}
2609
480b0c5b
GV
2610#endif /* HAVE_SOCKETS */
2611
2612
2613/* Shadow main io functions: we need to handle pipes and sockets more
2614 intelligently, and implement non-blocking mode as well. */
2615
2616int
2617sys_close (int fd)
2618{
2619 int rc;
2620
2621 if (fd < 0 || fd >= MAXDESC)
2622 {
2623 errno = EBADF;
2624 return -1;
2625 }
2626
2627 if (fd_info[fd].cp)
2628 {
2629 child_process * cp = fd_info[fd].cp;
2630
2631 fd_info[fd].cp = NULL;
2632
2633 if (CHILD_ACTIVE (cp))
2634 {
2635 /* if last descriptor to active child_process then cleanup */
2636 int i;
2637 for (i = 0; i < MAXDESC; i++)
2638 {
2639 if (i == fd)
2640 continue;
2641 if (fd_info[i].cp == cp)
2642 break;
2643 }
2644 if (i == MAXDESC)
2645 {
f249a012 2646#ifdef HAVE_SOCKETS
480b0c5b
GV
2647 if (fd_info[fd].flags & FILE_SOCKET)
2648 {
f249a012
RS
2649#ifndef SOCK_REPLACE_HANDLE
2650 if (winsock_lib == NULL) abort ();
480b0c5b
GV
2651
2652 pfn_shutdown (SOCK_HANDLE (fd), 2);
2653 rc = pfn_closesocket (SOCK_HANDLE (fd));
f249a012
RS
2654#endif
2655 winsock_inuse--; /* count open sockets */
480b0c5b
GV
2656 }
2657#endif
2658 delete_child (cp);
2659 }
2660 }
2661 }
2662
2663 /* Note that sockets do not need special treatment here (at least on
e9e23e23 2664 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
480b0c5b
GV
2665 closesocket is equivalent to CloseHandle, which is to be expected
2666 because socket handles are fully fledged kernel handles. */
2667 rc = _close (fd);
2668
2669 if (rc == 0)
2670 fd_info[fd].flags = 0;
2671
2672 return rc;
2673}
2674
2675int
2676sys_dup (int fd)
2677{
2678 int new_fd;
2679
2680 new_fd = _dup (fd);
2681 if (new_fd >= 0)
2682 {
2683 /* duplicate our internal info as well */
2684 fd_info[new_fd] = fd_info[fd];
2685 }
2686 return new_fd;
2687}
2688
2689
2690int
2691sys_dup2 (int src, int dst)
2692{
2693 int rc;
2694
2695 if (dst < 0 || dst >= MAXDESC)
2696 {
2697 errno = EBADF;
2698 return -1;
2699 }
2700
2701 /* make sure we close the destination first if it's a pipe or socket */
2702 if (src != dst && fd_info[dst].flags != 0)
2703 sys_close (dst);
2704
2705 rc = _dup2 (src, dst);
2706 if (rc == 0)
2707 {
2708 /* duplicate our internal info as well */
2709 fd_info[dst] = fd_info[src];
2710 }
2711 return rc;
2712}
2713
480b0c5b
GV
2714/* Unix pipe() has only one arg */
2715int
2716sys_pipe (int * phandles)
2717{
2718 int rc;
2719 unsigned flags;
2720 child_process * cp;
2721
76b3903d
GV
2722 /* make pipe handles non-inheritable; when we spawn a child, we
2723 replace the relevant handle with an inheritable one. Also put
2724 pipes into binary mode; we will do text mode translation ourselves
2725 if required. */
2726 rc = _pipe (phandles, 0, _O_NOINHERIT | _O_BINARY);
480b0c5b
GV
2727
2728 if (rc == 0)
2729 {
7664e306 2730 flags = FILE_PIPE | FILE_READ | FILE_BINARY;
480b0c5b
GV
2731 fd_info[phandles[0]].flags = flags;
2732
7664e306 2733 flags = FILE_PIPE | FILE_WRITE | FILE_BINARY;
480b0c5b
GV
2734 fd_info[phandles[1]].flags = flags;
2735 }
2736
2737 return rc;
2738}
2739
f7554349 2740/* From ntproc.c */
fbd6baed 2741extern Lisp_Object Vw32_pipe_read_delay;
f7554349 2742
480b0c5b
GV
2743/* Function to do blocking read of one byte, needed to implement
2744 select. It is only allowed on sockets and pipes. */
2745int
2746_sys_read_ahead (int fd)
2747{
2748 child_process * cp;
2749 int rc;
2750
2751 if (fd < 0 || fd >= MAXDESC)
2752 return STATUS_READ_ERROR;
2753
2754 cp = fd_info[fd].cp;
2755
2756 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
2757 return STATUS_READ_ERROR;
2758
2759 if ((fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET)) == 0
2760 || (fd_info[fd].flags & FILE_READ) == 0)
2761 {
2762 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe or socket!\n", fd));
2763 abort ();
2764 }
2765
2766 cp->status = STATUS_READ_IN_PROGRESS;
2767
2768 if (fd_info[fd].flags & FILE_PIPE)
f7554349 2769 {
f7554349
KH
2770 rc = _read (fd, &cp->chr, sizeof (char));
2771
2772 /* Give subprocess time to buffer some more output for us before
e9e23e23 2773 reporting that input is available; we need this because Windows 95
f7554349
KH
2774 connects DOS programs to pipes by making the pipe appear to be
2775 the normal console stdout - as a result most DOS programs will
2776 write to stdout without buffering, ie. one character at a
fbd6baed 2777 time. Even some W32 programs do this - "dir" in a command
f7554349
KH
2778 shell on NT is very slow if we don't do this. */
2779 if (rc > 0)
2780 {
fbd6baed 2781 int wait = XINT (Vw32_pipe_read_delay);
f7554349
KH
2782
2783 if (wait > 0)
2784 Sleep (wait);
2785 else if (wait < 0)
2786 while (++wait <= 0)
2787 /* Yield remainder of our time slice, effectively giving a
2788 temporary priority boost to the child process. */
2789 Sleep (0);
2790 }
2791 }
480b0c5b
GV
2792#ifdef HAVE_SOCKETS
2793 else if (fd_info[fd].flags & FILE_SOCKET)
2794 rc = pfn_recv (SOCK_HANDLE (fd), &cp->chr, sizeof (char), 0);
2795#endif
2796
2797 if (rc == sizeof (char))
2798 cp->status = STATUS_READ_SUCCEEDED;
2799 else
2800 cp->status = STATUS_READ_FAILED;
2801
2802 return cp->status;
2803}
2804
2805int
2806sys_read (int fd, char * buffer, unsigned int count)
2807{
2808 int nchars;
480b0c5b
GV
2809 int to_read;
2810 DWORD waiting;
76b3903d 2811 char * orig_buffer = buffer;
480b0c5b
GV
2812
2813 if (fd < 0 || fd >= MAXDESC)
2814 {
2815 errno = EBADF;
2816 return -1;
2817 }
2818
2819 if (fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET))
2820 {
2821 child_process *cp = fd_info[fd].cp;
2822
2823 if ((fd_info[fd].flags & FILE_READ) == 0)
2824 {
2825 errno = EBADF;
2826 return -1;
2827 }
2828
76b3903d
GV
2829 nchars = 0;
2830
2831 /* re-read CR carried over from last read */
2832 if (fd_info[fd].flags & FILE_LAST_CR)
2833 {
2834 if (fd_info[fd].flags & FILE_BINARY) abort ();
2835 *buffer++ = 0x0d;
2836 count--;
2837 nchars++;
f52eb3ef 2838 fd_info[fd].flags &= ~FILE_LAST_CR;
76b3903d
GV
2839 }
2840
480b0c5b
GV
2841 /* presence of a child_process structure means we are operating in
2842 non-blocking mode - otherwise we just call _read directly.
2843 Note that the child_process structure might be missing because
2844 reap_subprocess has been called; in this case the pipe is
2845 already broken, so calling _read on it is okay. */
2846 if (cp)
2847 {
2848 int current_status = cp->status;
2849
2850 switch (current_status)
2851 {
2852 case STATUS_READ_FAILED:
2853 case STATUS_READ_ERROR:
f52eb3ef
GV
2854 /* report normal EOF if nothing in buffer */
2855 if (nchars <= 0)
2856 fd_info[fd].flags |= FILE_AT_EOF;
2857 return nchars;
480b0c5b
GV
2858
2859 case STATUS_READ_READY:
2860 case STATUS_READ_IN_PROGRESS:
2861 DebPrint (("sys_read called when read is in progress\n"));
2862 errno = EWOULDBLOCK;
2863 return -1;
2864
2865 case STATUS_READ_SUCCEEDED:
2866 /* consume read-ahead char */
2867 *buffer++ = cp->chr;
2868 count--;
76b3903d 2869 nchars++;
480b0c5b
GV
2870 cp->status = STATUS_READ_ACKNOWLEDGED;
2871 ResetEvent (cp->char_avail);
2872
2873 case STATUS_READ_ACKNOWLEDGED:
2874 break;
2875
2876 default:
2877 DebPrint (("sys_read: bad status %d\n", current_status));
2878 errno = EBADF;
2879 return -1;
2880 }
2881
2882 if (fd_info[fd].flags & FILE_PIPE)
2883 {
2884 PeekNamedPipe ((HANDLE) _get_osfhandle (fd), NULL, 0, NULL, &waiting, NULL);
2885 to_read = min (waiting, (DWORD) count);
f52eb3ef
GV
2886
2887 if (to_read > 0)
2888 nchars += _read (fd, buffer, to_read);
480b0c5b
GV
2889 }
2890#ifdef HAVE_SOCKETS
2891 else /* FILE_SOCKET */
2892 {
f249a012 2893 if (winsock_lib == NULL) abort ();
480b0c5b
GV
2894
2895 /* do the equivalent of a non-blocking read */
2896 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONREAD, &waiting);
76b3903d 2897 if (waiting == 0 && nchars == 0)
480b0c5b
GV
2898 {
2899 h_errno = errno = EWOULDBLOCK;
2900 return -1;
2901 }
2902
480b0c5b
GV
2903 if (waiting)
2904 {
2905 /* always use binary mode for sockets */
76b3903d
GV
2906 int res = pfn_recv (SOCK_HANDLE (fd), buffer, count, 0);
2907 if (res == SOCKET_ERROR)
480b0c5b
GV
2908 {
2909 DebPrint(("sys_read.recv failed with error %d on socket %ld\n",
2910 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
76b3903d
GV
2911 set_errno ();
2912 return -1;
480b0c5b 2913 }
76b3903d 2914 nchars += res;
480b0c5b
GV
2915 }
2916 }
2917#endif
2918 }
2919 else
f52eb3ef
GV
2920 {
2921 int nread = _read (fd, buffer, count);
2922 if (nread >= 0)
2923 nchars += nread;
2924 else if (nchars == 0)
2925 nchars = nread;
2926 }
76b3903d 2927
f52eb3ef
GV
2928 if (nchars <= 0)
2929 fd_info[fd].flags |= FILE_AT_EOF;
76b3903d 2930 /* Perform text mode translation if required. */
f52eb3ef 2931 else if ((fd_info[fd].flags & FILE_BINARY) == 0)
76b3903d
GV
2932 {
2933 nchars = crlf_to_lf (nchars, orig_buffer);
2934 /* If buffer contains only CR, return that. To be absolutely
2935 sure we should attempt to read the next char, but in
2936 practice a CR to be followed by LF would not appear by
2937 itself in the buffer. */
2938 if (nchars > 1 && orig_buffer[nchars - 1] == 0x0d)
2939 {
2940 fd_info[fd].flags |= FILE_LAST_CR;
2941 nchars--;
2942 }
76b3903d 2943 }
480b0c5b
GV
2944 }
2945 else
2946 nchars = _read (fd, buffer, count);
2947
76b3903d 2948 return nchars;
480b0c5b
GV
2949}
2950
2951/* For now, don't bother with a non-blocking mode */
2952int
2953sys_write (int fd, const void * buffer, unsigned int count)
2954{
2955 int nchars;
2956
2957 if (fd < 0 || fd >= MAXDESC)
2958 {
2959 errno = EBADF;
2960 return -1;
2961 }
2962
2963 if (fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET))
76b3903d
GV
2964 {
2965 if ((fd_info[fd].flags & FILE_WRITE) == 0)
2966 {
2967 errno = EBADF;
2968 return -1;
2969 }
2970
2971 /* Perform text mode translation if required. */
2972 if ((fd_info[fd].flags & FILE_BINARY) == 0)
2973 {
2974 char * tmpbuf = alloca (count * 2);
2975 unsigned char * src = (void *)buffer;
2976 unsigned char * dst = tmpbuf;
2977 int nbytes = count;
2978
2979 while (1)
2980 {
2981 unsigned char *next;
2982 /* copy next line or remaining bytes */
2983 next = _memccpy (dst, src, '\n', nbytes);
2984 if (next)
2985 {
2986 /* copied one line ending with '\n' */
2987 int copied = next - dst;
2988 nbytes -= copied;
2989 src += copied;
2990 /* insert '\r' before '\n' */
2991 next[-1] = '\r';
2992 next[0] = '\n';
2993 dst = next + 1;
2994 count++;
2995 }
2996 else
2997 /* copied remaining partial line -> now finished */
2998 break;
2999 }
3000 buffer = tmpbuf;
3001 }
3002 }
3003
480b0c5b
GV
3004#ifdef HAVE_SOCKETS
3005 if (fd_info[fd].flags & FILE_SOCKET)
3006 {
f249a012 3007 if (winsock_lib == NULL) abort ();
480b0c5b
GV
3008 nchars = pfn_send (SOCK_HANDLE (fd), buffer, count, 0);
3009 if (nchars == SOCKET_ERROR)
3010 {
3011 DebPrint(("sys_read.send failed with error %d on socket %ld\n",
3012 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
3013 set_errno ();
3014 }
3015 }
3016 else
3017#endif
3018 nchars = _write (fd, buffer, count);
3019
3020 return nchars;
3021}
3022
f52eb3ef
GV
3023static void
3024check_windows_init_file ()
3025{
3026 extern int noninteractive, inhibit_window_system;
3027
3028 /* A common indication that Emacs is not installed properly is when
3029 it cannot find the Windows installation file. If this file does
3030 not exist in the expected place, tell the user. */
3031
d54abccd
GV
3032 if (!noninteractive && !inhibit_window_system)
3033 {
3034 extern Lisp_Object Vwindow_system, Vload_path, Qfile_exists_p;
a0b9c838 3035 Lisp_Object objs[2];
96ef7d42 3036 Lisp_Object full_load_path;
d54abccd
GV
3037 Lisp_Object init_file;
3038 int fd;
f52eb3ef 3039
a0b9c838
GV
3040 objs[0] = Vload_path;
3041 objs[1] = decode_env_path (0, (getenv ("EMACSLOADPATH")));
3042 full_load_path = Fappend (2, objs);
d54abccd 3043 init_file = build_string ("term/w32-win");
96ef7d42 3044 fd = openp (full_load_path, init_file, ".el:.elc", NULL, 0);
d54abccd
GV
3045 if (fd < 0)
3046 {
96ef7d42 3047 Lisp_Object load_path_print = Fprin1_to_string (full_load_path, Qnil);
d54abccd
GV
3048 char *init_file_name = XSTRING (init_file)->data;
3049 char *load_path = XSTRING (load_path_print)->data;
3050 char *buffer = alloca (1024);
3051
3052 sprintf (buffer,
3053 "The Emacs Windows initialization file \"%s.el\" "
3054 "could not be found in your Emacs installation. "
3055 "Emacs checked the following directories for this file:\n"
3056 "\n%s\n\n"
3057 "When Emacs cannot find this file, it usually means that it "
3058 "was not installed properly, or its distribution file was "
3059 "not unpacked properly.\nSee the README.W32 file in the "
3060 "top-level Emacs directory for more information.",
3061 init_file_name, load_path);
3062 MessageBox (NULL,
3063 buffer,
3064 "Emacs Abort Dialog",
3065 MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
f52eb3ef
GV
3066 /* Use the low-level Emacs abort. */
3067#undef abort
d54abccd
GV
3068 abort ();
3069 }
3070 else
3071 {
3072 close (fd);
3073 }
f52eb3ef 3074 }
f52eb3ef 3075}
480b0c5b
GV
3076
3077void
3078term_ntproc ()
3079{
3080#ifdef HAVE_SOCKETS
3081 /* shutdown the socket interface if necessary */
3082 term_winsock ();
3083#endif
3084}
3085
3086void
3087init_ntproc ()
3088{
3089#ifdef HAVE_SOCKETS
f249a012
RS
3090 /* Initialise the socket interface now if available and requested by
3091 the user by defining PRELOAD_WINSOCK; otherwise loading will be
fbd6baed 3092 delayed until open-network-stream is called (w32-has-winsock can
f249a012
RS
3093 also be used to dynamically load or reload winsock).
3094
3095 Conveniently, init_environment is called before us, so
3096 PRELOAD_WINSOCK can be set in the registry. */
3097
3098 /* Always initialize this correctly. */
3099 winsock_lib = NULL;
3100
3101 if (getenv ("PRELOAD_WINSOCK") != NULL)
3102 init_winsock (TRUE);
480b0c5b
GV
3103#endif
3104
3105 /* Initial preparation for subprocess support: replace our standard
3106 handles with non-inheritable versions. */
3107 {
3108 HANDLE parent;
3109 HANDLE stdin_save = INVALID_HANDLE_VALUE;
3110 HANDLE stdout_save = INVALID_HANDLE_VALUE;
3111 HANDLE stderr_save = INVALID_HANDLE_VALUE;
3112
3113 parent = GetCurrentProcess ();
3114
3115 /* ignore errors when duplicating and closing; typically the
3116 handles will be invalid when running as a gui program. */
3117 DuplicateHandle (parent,
3118 GetStdHandle (STD_INPUT_HANDLE),
3119 parent,
3120 &stdin_save,
3121 0,
3122 FALSE,
3123 DUPLICATE_SAME_ACCESS);
3124
3125 DuplicateHandle (parent,
3126 GetStdHandle (STD_OUTPUT_HANDLE),
3127 parent,
3128 &stdout_save,
3129 0,
3130 FALSE,
3131 DUPLICATE_SAME_ACCESS);
3132
3133 DuplicateHandle (parent,
3134 GetStdHandle (STD_ERROR_HANDLE),
3135 parent,
3136 &stderr_save,
3137 0,
3138 FALSE,
3139 DUPLICATE_SAME_ACCESS);
3140
3141 fclose (stdin);
3142 fclose (stdout);
3143 fclose (stderr);
3144
3145 if (stdin_save != INVALID_HANDLE_VALUE)
3146 _open_osfhandle ((long) stdin_save, O_TEXT);
3147 else
76b3903d
GV
3148 _open ("nul", O_TEXT | O_NOINHERIT | O_RDONLY);
3149 _fdopen (0, "r");
480b0c5b
GV
3150
3151 if (stdout_save != INVALID_HANDLE_VALUE)
3152 _open_osfhandle ((long) stdout_save, O_TEXT);
3153 else
76b3903d
GV
3154 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
3155 _fdopen (1, "w");
480b0c5b
GV
3156
3157 if (stderr_save != INVALID_HANDLE_VALUE)
3158 _open_osfhandle ((long) stderr_save, O_TEXT);
3159 else
76b3903d
GV
3160 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
3161 _fdopen (2, "w");
480b0c5b
GV
3162 }
3163
3164 /* unfortunately, atexit depends on implementation of malloc */
3165 /* atexit (term_ntproc); */
3166 signal (SIGABRT, term_ntproc);
76b3903d
GV
3167
3168 /* determine which drives are fixed, for GetCachedVolumeInformation */
3169 {
3170 /* GetDriveType must have trailing backslash. */
3171 char drive[] = "A:\\";
3172
3173 /* Loop over all possible drive letters */
3174 while (*drive <= 'Z')
3175 {
3176 /* Record if this drive letter refers to a fixed drive. */
3177 fixed_drives[DRIVE_INDEX (*drive)] =
3178 (GetDriveType (drive) == DRIVE_FIXED);
3179
3180 (*drive)++;
3181 }
3182 }
d54abccd
GV
3183
3184 /* Check to see if Emacs has been installed correctly. */
3185 check_windows_init_file ();
480b0c5b
GV
3186}
3187
3188/* end of nt.c */