(set-face-font): Call resolve-fontset-name on w32.
[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;
506 size -= len;
507
508 do
509 {
510 q = p;
511 p = strchr (q, '\\');
512 if (p) *p = '\0';
513 len = get_long_basename (full, o, size);
514 if (len > 0)
515 {
516 o += len;
517 size -= len;
518 if (p != NULL)
519 {
520 *p++ = '\\';
521 if (size < 2)
522 return FALSE;
523 *o++ = '\\';
524 size--;
525 *o = '\0';
526 }
527 }
528 else
529 return FALSE;
530 }
531 while (p != NULL && *p);
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
GV
641void
642init_environment ()
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;
761 char modname[MAX_PATH];
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);
770 }
771
480b0c5b
GV
772 init_user_info ();
773}
774
775/* We don't have scripts to automatically determine the system configuration
776 for Emacs before it's compiled, and we don't want to have to make the
777 user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
778 routine. */
779
780static char configuration_buffer[32];
781
782char *
783get_emacs_configuration (void)
784{
785 char *arch, *oem, *os;
786
787 /* Determine the processor type. */
788 switch (get_processor_type ())
789 {
790
791#ifdef PROCESSOR_INTEL_386
792 case PROCESSOR_INTEL_386:
793 case PROCESSOR_INTEL_486:
794 case PROCESSOR_INTEL_PENTIUM:
795 arch = "i386";
796 break;
797#endif
798
799#ifdef PROCESSOR_INTEL_860
800 case PROCESSOR_INTEL_860:
801 arch = "i860";
802 break;
803#endif
804
805#ifdef PROCESSOR_MIPS_R2000
806 case PROCESSOR_MIPS_R2000:
807 case PROCESSOR_MIPS_R3000:
808 case PROCESSOR_MIPS_R4000:
809 arch = "mips";
810 break;
811#endif
812
813#ifdef PROCESSOR_ALPHA_21064
814 case PROCESSOR_ALPHA_21064:
815 arch = "alpha";
816 break;
817#endif
818
819 default:
820 arch = "unknown";
821 break;
f332b293 822 }
480b0c5b
GV
823
824 /* Let oem be "*" until we figure out how to decode the OEM field. */
825 oem = "*";
826
76b3903d 827 os = (GetVersion () & OS_WIN95) ? "windows95" : "nt";
480b0c5b
GV
828
829 sprintf (configuration_buffer, "%s-%s-%s%d.%d", arch, oem, os,
fbd6baed 830 get_w32_major_version (), get_w32_minor_version ());
480b0c5b 831 return configuration_buffer;
f332b293
GV
832}
833
35f0d482
KH
834#include <sys/timeb.h>
835
836/* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
837void
838gettimeofday (struct timeval *tv, struct timezone *tz)
839{
840 struct _timeb tb;
841 _ftime (&tb);
842
843 tv->tv_sec = tb.time;
844 tv->tv_usec = tb.millitm * 1000L;
845 if (tz)
846 {
847 tz->tz_minuteswest = tb.timezone; /* minutes west of Greenwich */
848 tz->tz_dsttime = tb.dstflag; /* type of dst correction */
849 }
850}
35f0d482 851
480b0c5b 852/* ------------------------------------------------------------------------- */
fbd6baed 853/* IO support and wrapper functions for W32 API. */
480b0c5b 854/* ------------------------------------------------------------------------- */
95ed0025 855
480b0c5b
GV
856/* Place a wrapper around the MSVC version of ctime. It returns NULL
857 on network directories, so we handle that case here.
858 (Ulrich Leodolter, 1/11/95). */
859char *
860sys_ctime (const time_t *t)
861{
862 char *str = (char *) ctime (t);
863 return (str ? str : "Sun Jan 01 00:00:00 1970");
864}
865
866/* Emulate sleep...we could have done this with a define, but that
867 would necessitate including windows.h in the files that used it.
868 This is much easier. */
869void
870sys_sleep (int seconds)
871{
872 Sleep (seconds * 1000);
873}
874
76b3903d 875/* Internal MSVC functions for low-level descriptor munging */
480b0c5b
GV
876extern int __cdecl _set_osfhnd (int fd, long h);
877extern int __cdecl _free_osfhnd (int fd);
878
879/* parallel array of private info on file handles */
880filedesc fd_info [ MAXDESC ];
881
76b3903d
GV
882typedef struct volume_info_data {
883 struct volume_info_data * next;
884
885 /* time when info was obtained */
886 DWORD timestamp;
887
888 /* actual volume info */
889 char * root_dir;
480b0c5b
GV
890 DWORD serialnum;
891 DWORD maxcomp;
892 DWORD flags;
76b3903d
GV
893 char * name;
894 char * type;
895} volume_info_data;
896
897/* Global referenced by various functions. */
898static volume_info_data volume_info;
899
900/* Vector to indicate which drives are local and fixed (for which cached
901 data never expires). */
902static BOOL fixed_drives[26];
903
904/* Consider cached volume information to be stale if older than 10s,
905 at least for non-local drives. Info for fixed drives is never stale. */
906#define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
907#define VOLINFO_STILL_VALID( root_dir, info ) \
908 ( ( isalpha (root_dir[0]) && \
909 fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \
910 || GetTickCount () - info->timestamp < 10000 )
911
912/* Cache support functions. */
913
914/* Simple linked list with linear search is sufficient. */
915static volume_info_data *volume_cache = NULL;
916
917static volume_info_data *
918lookup_volume_info (char * root_dir)
919{
920 volume_info_data * info;
921
922 for (info = volume_cache; info; info = info->next)
923 if (stricmp (info->root_dir, root_dir) == 0)
924 break;
925 return info;
926}
927
928static void
929add_volume_info (char * root_dir, volume_info_data * info)
930{
931 info->root_dir = strdup (root_dir);
932 info->next = volume_cache;
933 volume_cache = info;
934}
935
936
937/* Wrapper for GetVolumeInformation, which uses caching to avoid
938 performance penalty (~2ms on 486 for local drives, 7.5ms for local
939 cdrom drive, ~5-10ms or more for remote drives on LAN). */
940volume_info_data *
941GetCachedVolumeInformation (char * root_dir)
942{
943 volume_info_data * info;
944 char default_root[ MAX_PATH ];
945
946 /* NULL for root_dir means use root from current directory. */
947 if (root_dir == NULL)
948 {
949 if (GetCurrentDirectory (MAX_PATH, default_root) == 0)
950 return NULL;
951 parse_root (default_root, &root_dir);
952 *root_dir = 0;
953 root_dir = default_root;
954 }
955
956 /* Local fixed drives can be cached permanently. Removable drives
957 cannot be cached permanently, since the volume name and serial
958 number (if nothing else) can change. Remote drives should be
959 treated as if they are removable, since there is no sure way to
960 tell whether they are or not. Also, the UNC association of drive
961 letters mapped to remote volumes can be changed at any time (even
962 by other processes) without notice.
963
964 As a compromise, so we can benefit from caching info for remote
965 volumes, we use a simple expiry mechanism to invalidate cache
966 entries that are more than ten seconds old. */
967
968#if 0
969 /* No point doing this, because WNetGetConnection is even slower than
970 GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
971 GetDriveType is about the only call of this type which does not
972 involve network access, and so is extremely quick). */
973
974 /* Map drive letter to UNC if remote. */
975 if ( isalpha( root_dir[0] ) && !fixed[ DRIVE_INDEX( root_dir[0] ) ] )
976 {
977 char remote_name[ 256 ];
978 char drive[3] = { root_dir[0], ':' };
979
980 if (WNetGetConnection (drive, remote_name, sizeof (remote_name))
981 == NO_ERROR)
982 /* do something */ ;
983 }
984#endif
985
986 info = lookup_volume_info (root_dir);
987
988 if (info == NULL || ! VOLINFO_STILL_VALID (root_dir, info))
989 {
990 char name[ 256 ];
991 DWORD serialnum;
992 DWORD maxcomp;
993 DWORD flags;
994 char type[ 256 ];
995
996 /* Info is not cached, or is stale. */
997 if (!GetVolumeInformation (root_dir,
998 name, sizeof (name),
999 &serialnum,
1000 &maxcomp,
1001 &flags,
1002 type, sizeof (type)))
1003 return NULL;
1004
1005 /* Cache the volume information for future use, overwriting existing
1006 entry if present. */
1007 if (info == NULL)
1008 {
1009 info = (volume_info_data *) xmalloc (sizeof (volume_info_data));
1010 add_volume_info (root_dir, info);
1011 }
1012 else
1013 {
1014 free (info->name);
1015 free (info->type);
1016 }
1017
1018 info->name = strdup (name);
1019 info->serialnum = serialnum;
1020 info->maxcomp = maxcomp;
1021 info->flags = flags;
1022 info->type = strdup (type);
1023 info->timestamp = GetTickCount ();
1024 }
1025
1026 return info;
1027}
480b0c5b
GV
1028
1029/* Get information on the volume where name is held; set path pointer to
1030 start of pathname in name (past UNC header\volume header if present). */
1031int
1032get_volume_info (const char * name, const char ** pPath)
95ed0025 1033{
480b0c5b
GV
1034 char temp[MAX_PATH];
1035 char *rootname = NULL; /* default to current volume */
76b3903d 1036 volume_info_data * info;
480b0c5b
GV
1037
1038 if (name == NULL)
1039 return FALSE;
1040
1041 /* find the root name of the volume if given */
1042 if (isalpha (name[0]) && name[1] == ':')
1043 {
1044 rootname = temp;
1045 temp[0] = *name++;
1046 temp[1] = *name++;
1047 temp[2] = '\\';
1048 temp[3] = 0;
1049 }
1050 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
95ed0025 1051 {
480b0c5b
GV
1052 char *str = temp;
1053 int slashes = 4;
1054 rootname = temp;
1055 do
1056 {
1057 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
1058 break;
1059 *str++ = *name++;
1060 }
1061 while ( *name );
1062
480b0c5b
GV
1063 *str++ = '\\';
1064 *str = 0;
95ed0025 1065 }
480b0c5b
GV
1066
1067 if (pPath)
1068 *pPath = name;
1069
76b3903d
GV
1070 info = GetCachedVolumeInformation (rootname);
1071 if (info != NULL)
95ed0025 1072 {
76b3903d
GV
1073 /* Set global referenced by other functions. */
1074 volume_info = *info;
480b0c5b 1075 return TRUE;
95ed0025 1076 }
480b0c5b
GV
1077 return FALSE;
1078}
1079
1080/* Determine if volume is FAT format (ie. only supports short 8.3
1081 names); also set path pointer to start of pathname in name. */
1082int
1083is_fat_volume (const char * name, const char ** pPath)
1084{
1085 if (get_volume_info (name, pPath))
1086 return (volume_info.maxcomp == 12);
1087 return FALSE;
1088}
1089
1090/* Map filename to a legal 8.3 name if necessary. */
1091const char *
fbd6baed 1092map_w32_filename (const char * name, const char ** pPath)
480b0c5b
GV
1093{
1094 static char shortname[MAX_PATH];
1095 char * str = shortname;
1096 char c;
480b0c5b 1097 char * path;
76b3903d 1098 const char * save_name = name;
480b0c5b
GV
1099
1100 if (is_fat_volume (name, &path)) /* truncate to 8.3 */
95ed0025 1101 {
480b0c5b
GV
1102 register int left = 8; /* maximum number of chars in part */
1103 register int extn = 0; /* extension added? */
1104 register int dots = 2; /* maximum number of dots allowed */
1105
1106 while (name < path)
1107 *str++ = *name++; /* skip past UNC header */
1108
1109 while ((c = *name++))
1110 {
1111 switch ( c )
1112 {
1113 case '\\':
1114 case '/':
1115 *str++ = '\\';
1116 extn = 0; /* reset extension flags */
1117 dots = 2; /* max 2 dots */
1118 left = 8; /* max length 8 for main part */
1119 break;
1120 case ':':
1121 *str++ = ':';
1122 extn = 0; /* reset extension flags */
1123 dots = 2; /* max 2 dots */
1124 left = 8; /* max length 8 for main part */
1125 break;
1126 case '.':
1127 if ( dots )
1128 {
1129 /* Convert path components of the form .xxx to _xxx,
1130 but leave . and .. as they are. This allows .emacs
1131 to be read as _emacs, for example. */
1132
1133 if (! *name ||
1134 *name == '.' ||
1135 IS_DIRECTORY_SEP (*name))
1136 {
1137 *str++ = '.';
1138 dots--;
1139 }
1140 else
1141 {
1142 *str++ = '_';
1143 left--;
1144 dots = 0;
1145 }
1146 }
1147 else if ( !extn )
1148 {
1149 *str++ = '.';
1150 extn = 1; /* we've got an extension */
1151 left = 3; /* 3 chars in extension */
1152 }
1153 else
1154 {
1155 /* any embedded dots after the first are converted to _ */
1156 *str++ = '_';
1157 }
1158 break;
1159 case '~':
1160 case '#': /* don't lose these, they're important */
1161 if ( ! left )
1162 str[-1] = c; /* replace last character of part */
1163 /* FALLTHRU */
1164 default:
1165 if ( left )
1166 {
1167 *str++ = tolower (c); /* map to lower case (looks nicer) */
1168 left--;
1169 dots = 0; /* started a path component */
1170 }
1171 break;
1172 }
1173 }
1174 *str = '\0';
fc85cb29
RS
1175 }
1176 else
1177 {
1178 strcpy (shortname, name);
1179 unixtodos_filename (shortname);
95ed0025 1180 }
480b0c5b
GV
1181
1182 if (pPath)
76b3903d 1183 *pPath = shortname + (path - save_name);
480b0c5b 1184
fc85cb29 1185 return shortname;
480b0c5b
GV
1186}
1187
b3308d2e
KH
1188static int
1189is_exec (const char * name)
1190{
1191 char * p = strrchr (name, '.');
1192 return
1193 (p != NULL
1194 && (stricmp (p, ".exe") == 0 ||
1195 stricmp (p, ".com") == 0 ||
1196 stricmp (p, ".bat") == 0 ||
1197 stricmp (p, ".cmd") == 0));
1198}
1199
76b3903d
GV
1200/* Emulate the Unix directory procedures opendir, closedir,
1201 and readdir. We can't use the procedures supplied in sysdep.c,
1202 so we provide them here. */
1203
1204struct direct dir_static; /* simulated directory contents */
1205static HANDLE dir_find_handle = INVALID_HANDLE_VALUE;
1206static int dir_is_fat;
1207static char dir_pathname[MAXPATHLEN+1];
1208static WIN32_FIND_DATA dir_find_data;
1209
9d3355d1
GV
1210/* Support shares on a network resource as subdirectories of a read-only
1211 root directory. */
1212static HANDLE wnet_enum_handle = INVALID_HANDLE_VALUE;
1213HANDLE open_unc_volume (char *);
1214char *read_unc_volume (HANDLE, char *, int);
1215void close_unc_volume (HANDLE);
1216
76b3903d
GV
1217DIR *
1218opendir (char *filename)
1219{
1220 DIR *dirp;
1221
1222 /* Opening is done by FindFirstFile. However, a read is inherent to
1223 this operation, so we defer the open until read time. */
1224
76b3903d
GV
1225 if (dir_find_handle != INVALID_HANDLE_VALUE)
1226 return NULL;
9d3355d1
GV
1227 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
1228 return NULL;
1229
1230 if (is_unc_volume (filename))
1231 {
1232 wnet_enum_handle = open_unc_volume (filename);
1233 if (wnet_enum_handle == INVALID_HANDLE_VALUE)
1234 return NULL;
1235 }
1236
1237 if (!(dirp = (DIR *) malloc (sizeof (DIR))))
1238 return NULL;
76b3903d
GV
1239
1240 dirp->dd_fd = 0;
1241 dirp->dd_loc = 0;
1242 dirp->dd_size = 0;
1243
1244 strncpy (dir_pathname, map_w32_filename (filename, NULL), MAXPATHLEN);
1245 dir_pathname[MAXPATHLEN] = '\0';
1246 dir_is_fat = is_fat_volume (filename, NULL);
1247
1248 return dirp;
1249}
1250
1251void
1252closedir (DIR *dirp)
1253{
1254 /* If we have a find-handle open, close it. */
1255 if (dir_find_handle != INVALID_HANDLE_VALUE)
1256 {
1257 FindClose (dir_find_handle);
1258 dir_find_handle = INVALID_HANDLE_VALUE;
1259 }
9d3355d1
GV
1260 else if (wnet_enum_handle != INVALID_HANDLE_VALUE)
1261 {
1262 close_unc_volume (wnet_enum_handle);
1263 wnet_enum_handle = INVALID_HANDLE_VALUE;
1264 }
76b3903d
GV
1265 xfree ((char *) dirp);
1266}
1267
1268struct direct *
1269readdir (DIR *dirp)
1270{
9d3355d1
GV
1271 if (wnet_enum_handle != INVALID_HANDLE_VALUE)
1272 {
1273 if (!read_unc_volume (wnet_enum_handle,
1274 dir_find_data.cFileName,
1275 MAX_PATH))
1276 return NULL;
1277 }
76b3903d 1278 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
9d3355d1 1279 else if (dir_find_handle == INVALID_HANDLE_VALUE)
76b3903d
GV
1280 {
1281 char filename[MAXNAMLEN + 3];
1282 int ln;
1283
1284 strcpy (filename, dir_pathname);
1285 ln = strlen (filename) - 1;
1286 if (!IS_DIRECTORY_SEP (filename[ln]))
1287 strcat (filename, "\\");
1288 strcat (filename, "*");
1289
1290 dir_find_handle = FindFirstFile (filename, &dir_find_data);
1291
1292 if (dir_find_handle == INVALID_HANDLE_VALUE)
1293 return NULL;
1294 }
1295 else
1296 {
1297 if (!FindNextFile (dir_find_handle, &dir_find_data))
1298 return NULL;
1299 }
1300
1301 /* Emacs never uses this value, so don't bother making it match
1302 value returned by stat(). */
1303 dir_static.d_ino = 1;
1304
1305 dir_static.d_reclen = sizeof (struct direct) - MAXNAMLEN + 3 +
1306 dir_static.d_namlen - dir_static.d_namlen % 4;
1307
1308 dir_static.d_namlen = strlen (dir_find_data.cFileName);
1309 strcpy (dir_static.d_name, dir_find_data.cFileName);
1310 if (dir_is_fat)
1311 _strlwr (dir_static.d_name);
1312 else if (!NILP (Vw32_downcase_file_names))
1313 {
1314 register char *p;
1315 for (p = dir_static.d_name; *p; p++)
1316 if (*p >= 'a' && *p <= 'z')
1317 break;
1318 if (!*p)
1319 _strlwr (dir_static.d_name);
1320 }
1321
1322 return &dir_static;
1323}
1324
9d3355d1
GV
1325HANDLE
1326open_unc_volume (char *path)
1327{
1328 NETRESOURCE nr;
1329 HANDLE henum;
1330 int result;
1331
1332 nr.dwScope = RESOURCE_GLOBALNET;
1333 nr.dwType = RESOURCETYPE_DISK;
1334 nr.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
1335 nr.dwUsage = RESOURCEUSAGE_CONTAINER;
1336 nr.lpLocalName = NULL;
1337 nr.lpRemoteName = map_w32_filename (path, NULL);
1338 nr.lpComment = NULL;
1339 nr.lpProvider = NULL;
1340
1341 result = WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
1342 RESOURCEUSAGE_CONNECTABLE, &nr, &henum);
1343
1344 if (result == NO_ERROR)
1345 return henum;
1346 else
1347 return INVALID_HANDLE_VALUE;
1348}
1349
1350char *
1351read_unc_volume (HANDLE henum, char *readbuf, int size)
1352{
1353 int count;
1354 int result;
1355 int bufsize = 512;
1356 char *buffer;
1357 char *ptr;
1358
1359 count = 1;
1360 buffer = alloca (bufsize);
1361 result = WNetEnumResource (wnet_enum_handle, &count, buffer, &bufsize);
1362 if (result != NO_ERROR)
1363 return NULL;
1364
1365 /* WNetEnumResource returns \\resource\share...skip forward to "share". */
1366 ptr = ((LPNETRESOURCE) buffer)->lpRemoteName;
1367 ptr += 2;
1368 while (*ptr && !IS_DIRECTORY_SEP (*ptr)) ptr++;
1369 ptr++;
1370
1371 strncpy (readbuf, ptr, size);
1372 return readbuf;
1373}
1374
1375void
1376close_unc_volume (HANDLE henum)
1377{
1378 if (henum != INVALID_HANDLE_VALUE)
1379 WNetCloseEnum (henum);
1380}
1381
1382DWORD
1383unc_volume_file_attributes (char *path)
1384{
1385 HANDLE henum;
1386 DWORD attrs;
1387
1388 henum = open_unc_volume (path);
1389 if (henum == INVALID_HANDLE_VALUE)
1390 return -1;
1391
1392 attrs = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY;
1393
1394 close_unc_volume (henum);
1395
1396 return attrs;
1397}
1398
480b0c5b
GV
1399
1400/* Shadow some MSVC runtime functions to map requests for long filenames
1401 to reasonable short names if necessary. This was originally added to
1402 permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
1403 long file names. */
1404
1405int
1406sys_access (const char * path, int mode)
1407{
b3308d2e
KH
1408 DWORD attributes;
1409
1410 /* MSVC implementation doesn't recognize D_OK. */
1411 path = map_w32_filename (path, NULL);
9d3355d1
GV
1412 if (is_unc_volume (path))
1413 {
1414 attributes = unc_volume_file_attributes (path);
1415 if (attributes == -1) {
1416 errno = EACCES;
1417 return -1;
1418 }
1419 }
1420 else if ((attributes = GetFileAttributes (path)) == -1)
b3308d2e
KH
1421 {
1422 /* Should try mapping GetLastError to errno; for now just indicate
1423 that path doesn't exist. */
1424 errno = EACCES;
1425 return -1;
1426 }
1427 if ((mode & X_OK) != 0 && !is_exec (path))
1428 {
1429 errno = EACCES;
1430 return -1;
1431 }
1432 if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0)
1433 {
1434 errno = EACCES;
1435 return -1;
1436 }
1437 if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
1438 {
1439 errno = EACCES;
1440 return -1;
1441 }
1442 return 0;
480b0c5b
GV
1443}
1444
1445int
1446sys_chdir (const char * path)
1447{
fbd6baed 1448 return _chdir (map_w32_filename (path, NULL));
480b0c5b
GV
1449}
1450
1451int
1452sys_chmod (const char * path, int mode)
1453{
fbd6baed 1454 return _chmod (map_w32_filename (path, NULL), mode);
480b0c5b
GV
1455}
1456
1457int
1458sys_creat (const char * path, int mode)
1459{
fbd6baed 1460 return _creat (map_w32_filename (path, NULL), mode);
480b0c5b
GV
1461}
1462
1463FILE *
1464sys_fopen(const char * path, const char * mode)
1465{
1466 int fd;
1467 int oflag;
1468 const char * mode_save = mode;
1469
1470 /* Force all file handles to be non-inheritable. This is necessary to
1471 ensure child processes don't unwittingly inherit handles that might
1472 prevent future file access. */
1473
1474 if (mode[0] == 'r')
1475 oflag = O_RDONLY;
1476 else if (mode[0] == 'w' || mode[0] == 'a')
1477 oflag = O_WRONLY | O_CREAT | O_TRUNC;
95ed0025 1478 else
480b0c5b
GV
1479 return NULL;
1480
1481 /* Only do simplistic option parsing. */
1482 while (*++mode)
1483 if (mode[0] == '+')
1484 {
1485 oflag &= ~(O_RDONLY | O_WRONLY);
1486 oflag |= O_RDWR;
1487 }
1488 else if (mode[0] == 'b')
1489 {
1490 oflag &= ~O_TEXT;
1491 oflag |= O_BINARY;
1492 }
1493 else if (mode[0] == 't')
1494 {
1495 oflag &= ~O_BINARY;
1496 oflag |= O_TEXT;
1497 }
1498 else break;
1499
fbd6baed 1500 fd = _open (map_w32_filename (path, NULL), oflag | _O_NOINHERIT, 0644);
480b0c5b
GV
1501 if (fd < 0)
1502 return NULL;
1503
76b3903d 1504 return _fdopen (fd, mode_save);
95ed0025 1505}
480b0c5b 1506
76b3903d 1507/* This only works on NTFS volumes, but is useful to have. */
480b0c5b 1508int
76b3903d 1509sys_link (const char * old, const char * new)
480b0c5b 1510{
76b3903d
GV
1511 HANDLE fileh;
1512 int result = -1;
1513 char oldname[MAX_PATH], newname[MAX_PATH];
1514
1515 if (old == NULL || new == NULL)
1516 {
1517 errno = ENOENT;
1518 return -1;
1519 }
1520
1521 strcpy (oldname, map_w32_filename (old, NULL));
1522 strcpy (newname, map_w32_filename (new, NULL));
1523
1524 fileh = CreateFile (oldname, 0, 0, NULL, OPEN_EXISTING,
1525 FILE_FLAG_BACKUP_SEMANTICS, NULL);
1526 if (fileh != INVALID_HANDLE_VALUE)
1527 {
1528 int wlen;
1529
1530 /* Confusingly, the "alternate" stream name field does not apply
1531 when restoring a hard link, and instead contains the actual
1532 stream data for the link (ie. the name of the link to create).
1533 The WIN32_STREAM_ID structure before the cStreamName field is
1534 the stream header, which is then immediately followed by the
1535 stream data. */
1536
1537 struct {
1538 WIN32_STREAM_ID wid;
1539 WCHAR wbuffer[MAX_PATH]; /* extra space for link name */
1540 } data;
1541
1542 wlen = MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, newname, -1,
1543 data.wid.cStreamName, MAX_PATH);
1544 if (wlen > 0)
1545 {
1546 LPVOID context = NULL;
1547 DWORD wbytes = 0;
1548
1549 data.wid.dwStreamId = BACKUP_LINK;
1550 data.wid.dwStreamAttributes = 0;
1551 data.wid.Size.LowPart = wlen * sizeof(WCHAR);
1552 data.wid.Size.HighPart = 0;
1553 data.wid.dwStreamNameSize = 0;
1554
1555 if (BackupWrite (fileh, (LPBYTE)&data,
1556 offsetof (WIN32_STREAM_ID, cStreamName)
1557 + data.wid.Size.LowPart,
1558 &wbytes, FALSE, FALSE, &context)
1559 && BackupWrite (fileh, NULL, 0, &wbytes, TRUE, FALSE, &context))
1560 {
1561 /* succeeded */
1562 result = 0;
1563 }
1564 else
1565 {
1566 /* Should try mapping GetLastError to errno; for now just
1567 indicate a general error (eg. links not supported). */
1568 errno = EINVAL; // perhaps EMLINK?
1569 }
1570 }
1571
1572 CloseHandle (fileh);
1573 }
1574 else
1575 errno = ENOENT;
1576
1577 return result;
480b0c5b
GV
1578}
1579
1580int
1581sys_mkdir (const char * path)
1582{
fbd6baed 1583 return _mkdir (map_w32_filename (path, NULL));
480b0c5b
GV
1584}
1585
9d1778b1
RS
1586/* Because of long name mapping issues, we need to implement this
1587 ourselves. Also, MSVC's _mktemp returns NULL when it can't generate
1588 a unique name, instead of setting the input template to an empty
1589 string.
1590
1591 Standard algorithm seems to be use pid or tid with a letter on the
1592 front (in place of the 6 X's) and cycle through the letters to find a
1593 unique name. We extend that to allow any reasonable character as the
1594 first of the 6 X's. */
480b0c5b
GV
1595char *
1596sys_mktemp (char * template)
1597{
9d1778b1
RS
1598 char * p;
1599 int i;
1600 unsigned uid = GetCurrentThreadId ();
1601 static char first_char[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
1602
1603 if (template == NULL)
1604 return NULL;
1605 p = template + strlen (template);
1606 i = 5;
1607 /* replace up to the last 5 X's with uid in decimal */
1608 while (--p >= template && p[0] == 'X' && --i >= 0)
1609 {
1610 p[0] = '0' + uid % 10;
1611 uid /= 10;
1612 }
1613
1614 if (i < 0 && p[0] == 'X')
1615 {
1616 i = 0;
1617 do
1618 {
1619 int save_errno = errno;
1620 p[0] = first_char[i];
1621 if (sys_access (template, 0) < 0)
1622 {
1623 errno = save_errno;
1624 return template;
1625 }
1626 }
1627 while (++i < sizeof (first_char));
1628 }
1629
1630 /* Template is badly formed or else we can't generate a unique name,
1631 so return empty string */
1632 template[0] = 0;
1633 return template;
480b0c5b
GV
1634}
1635
1636int
1637sys_open (const char * path, int oflag, int mode)
1638{
1639 /* Force all file handles to be non-inheritable. */
fbd6baed 1640 return _open (map_w32_filename (path, NULL), oflag | _O_NOINHERIT, mode);
480b0c5b
GV
1641}
1642
1643int
1644sys_rename (const char * oldname, const char * newname)
1645{
eb9ea53f 1646 int result;
b3308d2e 1647 char temp[MAX_PATH];
480b0c5b 1648
e9e23e23 1649 /* MoveFile on Windows 95 doesn't correctly change the short file name
5162ffce
MB
1650 alias in a number of circumstances (it is not easy to predict when
1651 just by looking at oldname and newname, unfortunately). In these
1652 cases, renaming through a temporary name avoids the problem.
1653
e9e23e23 1654 A second problem on Windows 95 is that renaming through a temp name when
5162ffce
MB
1655 newname is uppercase fails (the final long name ends up in
1656 lowercase, although the short alias might be uppercase) UNLESS the
1657 long temp name is not 8.3.
1658
e9e23e23 1659 So, on Windows 95 we always rename through a temp name, and we make sure
5162ffce 1660 the temp name has a long extension to ensure correct renaming. */
480b0c5b 1661
fbd6baed 1662 strcpy (temp, map_w32_filename (oldname, NULL));
480b0c5b 1663
76b3903d 1664 if (os_subtype == OS_WIN95)
480b0c5b 1665 {
b3308d2e 1666 char * o;
480b0c5b 1667 char * p;
b3308d2e
KH
1668 int i = 0;
1669
1670 oldname = map_w32_filename (oldname, NULL);
1671 if (o = strrchr (oldname, '\\'))
1672 o++;
1673 else
1674 o = (char *) oldname;
480b0c5b 1675
480b0c5b
GV
1676 if (p = strrchr (temp, '\\'))
1677 p++;
1678 else
1679 p = temp;
b3308d2e
KH
1680
1681 do
1682 {
1683 /* Force temp name to require a manufactured 8.3 alias - this
1684 seems to make the second rename work properly. */
f313ee82 1685 sprintf (p, "_.%s.%u", o, i);
b3308d2e 1686 i++;
58f0cb7e 1687 result = rename (oldname, temp);
b3308d2e
KH
1688 }
1689 /* This loop must surely terminate! */
f313ee82 1690 while (result < 0 && (errno == EEXIST || errno == EACCES));
58f0cb7e 1691 if (result < 0)
480b0c5b
GV
1692 return -1;
1693 }
1694
1695 /* Emulate Unix behaviour - newname is deleted if it already exists
5162ffce 1696 (at least if it is a file; don't do this for directories).
76b3903d 1697
b3308d2e
KH
1698 Since we mustn't do this if we are just changing the case of the
1699 file name (we would end up deleting the file we are trying to
1700 rename!), we let rename detect if the destination file already
1701 exists - that way we avoid the possible pitfalls of trying to
1702 determine ourselves whether two names really refer to the same
1703 file, which is not always possible in the general case. (Consider
1704 all the permutations of shared or subst'd drives, etc.) */
1705
1706 newname = map_w32_filename (newname, NULL);
eb9ea53f 1707 result = rename (temp, newname);
b3308d2e
KH
1708
1709 if (result < 0
f313ee82 1710 && (errno == EEXIST || errno == EACCES)
b3308d2e
KH
1711 && _chmod (newname, 0666) == 0
1712 && _unlink (newname) == 0)
1713 result = rename (temp, newname);
480b0c5b 1714
eb9ea53f 1715 return result;
480b0c5b
GV
1716}
1717
1718int
1719sys_rmdir (const char * path)
1720{
fbd6baed 1721 return _rmdir (map_w32_filename (path, NULL));
480b0c5b
GV
1722}
1723
1724int
1725sys_unlink (const char * path)
1726{
16bb7578
GV
1727 path = map_w32_filename (path, NULL);
1728
1729 /* On Unix, unlink works without write permission. */
1730 _chmod (path, 0666);
1731 return _unlink (path);
480b0c5b
GV
1732}
1733
1734static FILETIME utc_base_ft;
1735static long double utc_base;
1736static int init = 0;
1737
1738static time_t
1739convert_time (FILETIME ft)
1740{
1741 long double ret;
1742
1743 if (!init)
1744 {
1745 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
1746 SYSTEMTIME st;
1747
1748 st.wYear = 1970;
1749 st.wMonth = 1;
1750 st.wDay = 1;
1751 st.wHour = 0;
1752 st.wMinute = 0;
1753 st.wSecond = 0;
1754 st.wMilliseconds = 0;
1755
1756 SystemTimeToFileTime (&st, &utc_base_ft);
1757 utc_base = (long double) utc_base_ft.dwHighDateTime
1758 * 4096 * 1024 * 1024 + utc_base_ft.dwLowDateTime;
1759 init = 1;
1760 }
1761
1762 if (CompareFileTime (&ft, &utc_base_ft) < 0)
1763 return 0;
1764
1765 ret = (long double) ft.dwHighDateTime * 4096 * 1024 * 1024 + ft.dwLowDateTime;
1766 ret -= utc_base;
1767 return (time_t) (ret * 1e-7);
1768}
1769
480b0c5b
GV
1770void
1771convert_from_time_t (time_t time, FILETIME * pft)
1772{
1773 long double tmp;
1774
1775 if (!init)
1776 {
1777 /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
1778 SYSTEMTIME st;
1779
1780 st.wYear = 1970;
1781 st.wMonth = 1;
1782 st.wDay = 1;
1783 st.wHour = 0;
1784 st.wMinute = 0;
1785 st.wSecond = 0;
1786 st.wMilliseconds = 0;
1787
1788 SystemTimeToFileTime (&st, &utc_base_ft);
1789 utc_base = (long double) utc_base_ft.dwHighDateTime
1790 * 4096 * 1024 * 1024 + utc_base_ft.dwLowDateTime;
1791 init = 1;
1792 }
1793
1794 /* time in 100ns units since 1-Jan-1601 */
1795 tmp = (long double) time * 1e7 + utc_base;
1796 pft->dwHighDateTime = (DWORD) (tmp / (4096.0 * 1024 * 1024));
16bb7578 1797 pft->dwLowDateTime = (DWORD) (tmp - (4096.0 * 1024 * 1024) * pft->dwHighDateTime);
480b0c5b 1798}
480b0c5b 1799
76b3903d
GV
1800#if 0
1801/* No reason to keep this; faking inode values either by hashing or even
1802 using the file index from GetInformationByHandle, is not perfect and
1803 so by default Emacs doesn't use the inode values on Windows.
1804 Instead, we now determine file-truename correctly (except for
1805 possible drive aliasing etc). */
1806
1807/* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
480b0c5b 1808static unsigned
76b3903d 1809hashval (const unsigned char * str)
480b0c5b
GV
1810{
1811 unsigned h = 0;
480b0c5b
GV
1812 while (*str)
1813 {
1814 h = (h << 4) + *str++;
76b3903d 1815 h ^= (h >> 28);
480b0c5b
GV
1816 }
1817 return h;
1818}
1819
1820/* Return the hash value of the canonical pathname, excluding the
1821 drive/UNC header, to get a hopefully unique inode number. */
76b3903d 1822static DWORD
480b0c5b
GV
1823generate_inode_val (const char * name)
1824{
1825 char fullname[ MAX_PATH ];
1826 char * p;
1827 unsigned hash;
1828
76b3903d
GV
1829 /* Get the truly canonical filename, if it exists. (Note: this
1830 doesn't resolve aliasing due to subst commands, or recognise hard
1831 links. */
1832 if (!w32_get_long_filename ((char *)name, fullname, MAX_PATH))
1833 abort ();
1834
1835 parse_root (fullname, &p);
fbd6baed 1836 /* Normal W32 filesystems are still case insensitive. */
480b0c5b 1837 _strlwr (p);
76b3903d 1838 return hashval (p);
480b0c5b
GV
1839}
1840
76b3903d
GV
1841#endif
1842
480b0c5b
GV
1843/* MSVC stat function can't cope with UNC names and has other bugs, so
1844 replace it with our own. This also allows us to calculate consistent
1845 inode values without hacks in the main Emacs code. */
1846int
1847stat (const char * path, struct stat * buf)
1848{
eb9ea53f 1849 char *name, *r;
480b0c5b
GV
1850 WIN32_FIND_DATA wfd;
1851 HANDLE fh;
76b3903d 1852 DWORD fake_inode;
480b0c5b
GV
1853 int permission;
1854 int len;
1855 int rootdir = FALSE;
1856
1857 if (path == NULL || buf == NULL)
1858 {
1859 errno = EFAULT;
1860 return -1;
1861 }
1862
fbd6baed 1863 name = (char *) map_w32_filename (path, &path);
bb1584c8
RS
1864 /* must be valid filename, no wild cards or other illegal characters */
1865 if (strpbrk (name, "*?|<>\""))
480b0c5b
GV
1866 {
1867 errno = ENOENT;
1868 return -1;
1869 }
1870
eb9ea53f
GV
1871 /* If name is "c:/.." or "/.." then stat "c:/" or "/". */
1872 r = IS_DEVICE_SEP (name[1]) ? &name[2] : name;
1873 if (IS_DIRECTORY_SEP (r[0]) && r[1] == '.' && r[2] == '.' && r[3] == '\0')
1874 {
1875 r[1] = r[2] = '\0';
1876 }
1877
480b0c5b
GV
1878 /* Remove trailing directory separator, unless name is the root
1879 directory of a drive or UNC volume in which case ensure there
1880 is a trailing separator. */
1881 len = strlen (name);
1882 rootdir = (path >= name + len - 1
1883 && (IS_DIRECTORY_SEP (*path) || *path == 0));
1884 name = strcpy (alloca (len + 2), name);
1885
9d3355d1
GV
1886 if (is_unc_volume (name))
1887 {
1888 DWORD attrs = unc_volume_file_attributes (name);
1889
1890 if (attrs == -1)
1891 return -1;
1892
1893 memset (&wfd, 0, sizeof (wfd));
1894 wfd.dwFileAttributes = attrs;
1895 wfd.ftCreationTime = utc_base_ft;
1896 wfd.ftLastAccessTime = utc_base_ft;
1897 wfd.ftLastWriteTime = utc_base_ft;
1898 strcpy (wfd.cFileName, name);
1899 }
1900 else if (rootdir)
480b0c5b
GV
1901 {
1902 if (!IS_DIRECTORY_SEP (name[len-1]))
1903 strcat (name, "\\");
1904 if (GetDriveType (name) < 2)
1905 {
1906 errno = ENOENT;
1907 return -1;
1908 }
1909 memset (&wfd, 0, sizeof (wfd));
1910 wfd.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
1911 wfd.ftCreationTime = utc_base_ft;
1912 wfd.ftLastAccessTime = utc_base_ft;
1913 wfd.ftLastWriteTime = utc_base_ft;
1914 strcpy (wfd.cFileName, name);
1915 }
1916 else
1917 {
1918 if (IS_DIRECTORY_SEP (name[len-1]))
1919 name[len - 1] = 0;
76b3903d
GV
1920
1921 /* (This is hacky, but helps when doing file completions on
1922 network drives.) Optimize by using information available from
1923 active readdir if possible. */
1924 if (dir_find_handle != INVALID_HANDLE_VALUE
1925 && (len = strlen (dir_pathname)),
1926 strnicmp (name, dir_pathname, len) == 0
1927 && IS_DIRECTORY_SEP (name[len])
1928 && stricmp (name + len + 1, dir_static.d_name) == 0)
480b0c5b 1929 {
76b3903d
GV
1930 /* This was the last entry returned by readdir. */
1931 wfd = dir_find_data;
1932 }
1933 else
1934 {
1935 fh = FindFirstFile (name, &wfd);
1936 if (fh == INVALID_HANDLE_VALUE)
1937 {
1938 errno = ENOENT;
1939 return -1;
1940 }
1941 FindClose (fh);
480b0c5b 1942 }
480b0c5b
GV
1943 }
1944
1945 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1946 {
1947 buf->st_mode = _S_IFDIR;
1948 buf->st_nlink = 2; /* doesn't really matter */
76b3903d 1949 fake_inode = 0; /* this doesn't either I think */
480b0c5b 1950 }
710ea1b8
RS
1951 else if (!NILP (Vw32_get_true_file_attributes)
1952 /* No access rights required to get info. */
1953 && (fh = CreateFile (name, 0, 0, NULL, OPEN_EXISTING, 0, NULL))
1954 != INVALID_HANDLE_VALUE)
480b0c5b 1955 {
480b0c5b
GV
1956 /* This is more accurate in terms of gettting the correct number
1957 of links, but is quite slow (it is noticable when Emacs is
1958 making a list of file name completions). */
1959 BY_HANDLE_FILE_INFORMATION info;
1960
480b0c5b
GV
1961 if (GetFileInformationByHandle (fh, &info))
1962 {
1963 switch (GetFileType (fh))
1964 {
1965 case FILE_TYPE_DISK:
1966 buf->st_mode = _S_IFREG;
1967 break;
1968 case FILE_TYPE_PIPE:
1969 buf->st_mode = _S_IFIFO;
1970 break;
1971 case FILE_TYPE_CHAR:
1972 case FILE_TYPE_UNKNOWN:
1973 default:
1974 buf->st_mode = _S_IFCHR;
1975 }
1976 buf->st_nlink = info.nNumberOfLinks;
76b3903d
GV
1977 /* Might as well use file index to fake inode values, but this
1978 is not guaranteed to be unique unless we keep a handle open
1979 all the time (even then there are situations where it is
1980 not unique). Reputedly, there are at most 48 bits of info
1981 (on NTFS, presumably less on FAT). */
1982 fake_inode = info.nFileIndexLow ^ info.nFileIndexHigh;
480b0c5b
GV
1983 CloseHandle (fh);
1984 }
1985 else
1986 {
1987 errno = EACCES;
1988 return -1;
1989 }
76b3903d
GV
1990 }
1991 else
1992 {
1993 /* Don't bother to make this information more accurate. */
480b0c5b
GV
1994 buf->st_mode = _S_IFREG;
1995 buf->st_nlink = 1;
76b3903d
GV
1996 fake_inode = 0;
1997 }
1998
1999#if 0
2000 /* Not sure if there is any point in this. */
2001 if (!NILP (Vw32_generate_fake_inodes))
2002 fake_inode = generate_inode_val (name);
2003 else if (fake_inode == 0)
2004 {
2005 /* For want of something better, try to make everything unique. */
2006 static DWORD gen_num = 0;
2007 fake_inode = ++gen_num;
480b0c5b 2008 }
76b3903d
GV
2009#endif
2010
2011 /* MSVC defines _ino_t to be short; other libc's might not. */
2012 if (sizeof (buf->st_ino) == 2)
2013 buf->st_ino = fake_inode ^ (fake_inode >> 16);
2014 else
2015 buf->st_ino = fake_inode;
480b0c5b
GV
2016
2017 /* consider files to belong to current user */
2018 buf->st_uid = the_passwd.pw_uid;
2019 buf->st_gid = the_passwd.pw_gid;
2020
fbd6baed 2021 /* volume_info is set indirectly by map_w32_filename */
480b0c5b
GV
2022 buf->st_dev = volume_info.serialnum;
2023 buf->st_rdev = volume_info.serialnum;
2024
480b0c5b
GV
2025
2026 buf->st_size = wfd.nFileSizeLow;
2027
2028 /* Convert timestamps to Unix format. */
2029 buf->st_mtime = convert_time (wfd.ftLastWriteTime);
2030 buf->st_atime = convert_time (wfd.ftLastAccessTime);
2031 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
2032 buf->st_ctime = convert_time (wfd.ftCreationTime);
2033 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
2034
2035 /* determine rwx permissions */
2036 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
2037 permission = _S_IREAD;
2038 else
2039 permission = _S_IREAD | _S_IWRITE;
2040
2041 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
2042 permission |= _S_IEXEC;
b3308d2e
KH
2043 else if (is_exec (name))
2044 permission |= _S_IEXEC;
480b0c5b
GV
2045
2046 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
2047
2048 return 0;
2049}
2050
16bb7578
GV
2051/* Provide fstat and utime as well as stat for consistent handling of
2052 file timestamps. */
2053int
2054fstat (int desc, struct stat * buf)
2055{
2056 HANDLE fh = (HANDLE) _get_osfhandle (desc);
2057 BY_HANDLE_FILE_INFORMATION info;
2058 DWORD fake_inode;
2059 int permission;
2060
2061 switch (GetFileType (fh) & ~FILE_TYPE_REMOTE)
2062 {
2063 case FILE_TYPE_DISK:
2064 buf->st_mode = _S_IFREG;
2065 if (!GetFileInformationByHandle (fh, &info))
2066 {
2067 errno = EACCES;
2068 return -1;
2069 }
2070 break;
2071 case FILE_TYPE_PIPE:
2072 buf->st_mode = _S_IFIFO;
2073 goto non_disk;
2074 case FILE_TYPE_CHAR:
2075 case FILE_TYPE_UNKNOWN:
2076 default:
2077 buf->st_mode = _S_IFCHR;
2078 non_disk:
2079 memset (&info, 0, sizeof (info));
2080 info.dwFileAttributes = 0;
2081 info.ftCreationTime = utc_base_ft;
2082 info.ftLastAccessTime = utc_base_ft;
2083 info.ftLastWriteTime = utc_base_ft;
2084 }
2085
2086 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
2087 {
2088 buf->st_mode = _S_IFDIR;
2089 buf->st_nlink = 2; /* doesn't really matter */
2090 fake_inode = 0; /* this doesn't either I think */
2091 }
2092 else
2093 {
2094 buf->st_nlink = info.nNumberOfLinks;
2095 /* Might as well use file index to fake inode values, but this
2096 is not guaranteed to be unique unless we keep a handle open
2097 all the time (even then there are situations where it is
2098 not unique). Reputedly, there are at most 48 bits of info
2099 (on NTFS, presumably less on FAT). */
2100 fake_inode = info.nFileIndexLow ^ info.nFileIndexHigh;
2101 }
2102
2103 /* MSVC defines _ino_t to be short; other libc's might not. */
2104 if (sizeof (buf->st_ino) == 2)
2105 buf->st_ino = fake_inode ^ (fake_inode >> 16);
2106 else
2107 buf->st_ino = fake_inode;
2108
2109 /* consider files to belong to current user */
2110 buf->st_uid = 0;
2111 buf->st_gid = 0;
2112
2113 buf->st_dev = info.dwVolumeSerialNumber;
2114 buf->st_rdev = info.dwVolumeSerialNumber;
2115
2116 buf->st_size = info.nFileSizeLow;
2117
2118 /* Convert timestamps to Unix format. */
2119 buf->st_mtime = convert_time (info.ftLastWriteTime);
2120 buf->st_atime = convert_time (info.ftLastAccessTime);
2121 if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
2122 buf->st_ctime = convert_time (info.ftCreationTime);
2123 if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
2124
2125 /* determine rwx permissions */
2126 if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
2127 permission = _S_IREAD;
2128 else
2129 permission = _S_IREAD | _S_IWRITE;
2130
2131 if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
2132 permission |= _S_IEXEC;
2133 else
2134 {
2135#if 0 /* no way of knowing the filename */
2136 char * p = strrchr (name, '.');
2137 if (p != NULL &&
2138 (stricmp (p, ".exe") == 0 ||
2139 stricmp (p, ".com") == 0 ||
2140 stricmp (p, ".bat") == 0 ||
2141 stricmp (p, ".cmd") == 0))
2142 permission |= _S_IEXEC;
2143#endif
2144 }
2145
2146 buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
2147
2148 return 0;
2149}
2150
2151int
2152utime (const char *name, struct utimbuf *times)
2153{
2154 struct utimbuf deftime;
2155 HANDLE fh;
2156 FILETIME mtime;
2157 FILETIME atime;
2158
2159 if (times == NULL)
2160 {
2161 deftime.modtime = deftime.actime = time (NULL);
2162 times = &deftime;
2163 }
2164
2165 /* Need write access to set times. */
2166 fh = CreateFile (name, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
2167 0, OPEN_EXISTING, 0, NULL);
2168 if (fh)
2169 {
2170 convert_from_time_t (times->actime, &atime);
2171 convert_from_time_t (times->modtime, &mtime);
2172 if (!SetFileTime (fh, NULL, &atime, &mtime))
2173 {
2174 CloseHandle (fh);
2175 errno = EACCES;
2176 return -1;
2177 }
2178 CloseHandle (fh);
2179 }
2180 else
2181 {
2182 errno = EINVAL;
2183 return -1;
2184 }
2185 return 0;
2186}
2187
480b0c5b
GV
2188#ifdef HAVE_SOCKETS
2189
2190/* Wrappers for winsock functions to map between our file descriptors
2191 and winsock's handles; also set h_errno for convenience.
2192
2193 To allow Emacs to run on systems which don't have winsock support
2194 installed, we dynamically link to winsock on startup if present, and
2195 otherwise provide the minimum necessary functionality
2196 (eg. gethostname). */
2197
2198/* function pointers for relevant socket functions */
2199int (PASCAL *pfn_WSAStartup) (WORD wVersionRequired, LPWSADATA lpWSAData);
2200void (PASCAL *pfn_WSASetLastError) (int iError);
2201int (PASCAL *pfn_WSAGetLastError) (void);
2202int (PASCAL *pfn_socket) (int af, int type, int protocol);
2203int (PASCAL *pfn_bind) (SOCKET s, const struct sockaddr *addr, int namelen);
2204int (PASCAL *pfn_connect) (SOCKET s, const struct sockaddr *addr, int namelen);
2205int (PASCAL *pfn_ioctlsocket) (SOCKET s, long cmd, u_long *argp);
2206int (PASCAL *pfn_recv) (SOCKET s, char * buf, int len, int flags);
2207int (PASCAL *pfn_send) (SOCKET s, const char * buf, int len, int flags);
2208int (PASCAL *pfn_closesocket) (SOCKET s);
2209int (PASCAL *pfn_shutdown) (SOCKET s, int how);
2210int (PASCAL *pfn_WSACleanup) (void);
2211
2212u_short (PASCAL *pfn_htons) (u_short hostshort);
2213u_short (PASCAL *pfn_ntohs) (u_short netshort);
2214unsigned long (PASCAL *pfn_inet_addr) (const char * cp);
2215int (PASCAL *pfn_gethostname) (char * name, int namelen);
2216struct hostent * (PASCAL *pfn_gethostbyname) (const char * name);
2217struct servent * (PASCAL *pfn_getservbyname) (const char * name, const char * proto);
f1614061
RS
2218
2219/* SetHandleInformation is only needed to make sockets non-inheritable. */
2220BOOL (WINAPI *pfn_SetHandleInformation) (HANDLE object, DWORD mask, DWORD flags);
2221#ifndef HANDLE_FLAG_INHERIT
2222#define HANDLE_FLAG_INHERIT 1
2223#endif
480b0c5b 2224
f249a012
RS
2225HANDLE winsock_lib;
2226static int winsock_inuse;
480b0c5b 2227
f249a012 2228BOOL
480b0c5b
GV
2229term_winsock (void)
2230{
f249a012 2231 if (winsock_lib != NULL && winsock_inuse == 0)
480b0c5b 2232 {
f249a012
RS
2233 /* Not sure what would cause WSAENETDOWN, or even if it can happen
2234 after WSAStartup returns successfully, but it seems reasonable
2235 to allow unloading winsock anyway in that case. */
2236 if (pfn_WSACleanup () == 0 ||
2237 pfn_WSAGetLastError () == WSAENETDOWN)
2238 {
2239 if (FreeLibrary (winsock_lib))
2240 winsock_lib = NULL;
2241 return TRUE;
2242 }
480b0c5b 2243 }
f249a012 2244 return FALSE;
480b0c5b
GV
2245}
2246
f249a012
RS
2247BOOL
2248init_winsock (int load_now)
480b0c5b
GV
2249{
2250 WSADATA winsockData;
2251
f249a012
RS
2252 if (winsock_lib != NULL)
2253 return TRUE;
f1614061
RS
2254
2255 pfn_SetHandleInformation = NULL;
2256 pfn_SetHandleInformation
2257 = (void *) GetProcAddress (GetModuleHandle ("kernel32.dll"),
2258 "SetHandleInformation");
2259
480b0c5b
GV
2260 winsock_lib = LoadLibrary ("wsock32.dll");
2261
2262 if (winsock_lib != NULL)
2263 {
2264 /* dynamically link to socket functions */
2265
2266#define LOAD_PROC(fn) \
2267 if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
2268 goto fail;
2269
2270 LOAD_PROC( WSAStartup );
2271 LOAD_PROC( WSASetLastError );
2272 LOAD_PROC( WSAGetLastError );
2273 LOAD_PROC( socket );
2274 LOAD_PROC( bind );
2275 LOAD_PROC( connect );
2276 LOAD_PROC( ioctlsocket );
2277 LOAD_PROC( recv );
2278 LOAD_PROC( send );
2279 LOAD_PROC( closesocket );
2280 LOAD_PROC( shutdown );
2281 LOAD_PROC( htons );
2282 LOAD_PROC( ntohs );
2283 LOAD_PROC( inet_addr );
2284 LOAD_PROC( gethostname );
2285 LOAD_PROC( gethostbyname );
2286 LOAD_PROC( getservbyname );
2287 LOAD_PROC( WSACleanup );
2288
f249a012
RS
2289#undef LOAD_PROC
2290
480b0c5b
GV
2291 /* specify version 1.1 of winsock */
2292 if (pfn_WSAStartup (0x101, &winsockData) == 0)
2293 {
f249a012
RS
2294 if (winsockData.wVersion != 0x101)
2295 goto fail;
2296
2297 if (!load_now)
2298 {
2299 /* Report that winsock exists and is usable, but leave
2300 socket functions disabled. I am assuming that calling
2301 WSAStartup does not require any network interaction,
2302 and in particular does not cause or require a dial-up
2303 connection to be established. */
2304
2305 pfn_WSACleanup ();
2306 FreeLibrary (winsock_lib);
2307 winsock_lib = NULL;
2308 }
2309 winsock_inuse = 0;
2310 return TRUE;
480b0c5b
GV
2311 }
2312
2313 fail:
2314 FreeLibrary (winsock_lib);
f249a012 2315 winsock_lib = NULL;
480b0c5b 2316 }
f249a012
RS
2317
2318 return FALSE;
480b0c5b
GV
2319}
2320
2321
2322int h_errno = 0;
2323
2324/* function to set h_errno for compatability; map winsock error codes to
2325 normal system codes where they overlap (non-overlapping definitions
2326 are already in <sys/socket.h> */
2327static void set_errno ()
2328{
f249a012 2329 if (winsock_lib == NULL)
480b0c5b
GV
2330 h_errno = EINVAL;
2331 else
2332 h_errno = pfn_WSAGetLastError ();
2333
2334 switch (h_errno)
2335 {
2336 case WSAEACCES: h_errno = EACCES; break;
2337 case WSAEBADF: h_errno = EBADF; break;
2338 case WSAEFAULT: h_errno = EFAULT; break;
2339 case WSAEINTR: h_errno = EINTR; break;
2340 case WSAEINVAL: h_errno = EINVAL; break;
2341 case WSAEMFILE: h_errno = EMFILE; break;
2342 case WSAENAMETOOLONG: h_errno = ENAMETOOLONG; break;
2343 case WSAENOTEMPTY: h_errno = ENOTEMPTY; break;
2344 }
2345 errno = h_errno;
2346}
2347
2348static void check_errno ()
2349{
f249a012 2350 if (h_errno == 0 && winsock_lib != NULL)
480b0c5b
GV
2351 pfn_WSASetLastError (0);
2352}
2353
2354/* [andrewi 3-May-96] I've had conflicting results using both methods,
2355 but I believe the method of keeping the socket handle separate (and
2356 insuring it is not inheritable) is the correct one. */
2357
2358//#define SOCK_REPLACE_HANDLE
2359
2360#ifdef SOCK_REPLACE_HANDLE
2361#define SOCK_HANDLE(fd) ((SOCKET) _get_osfhandle (fd))
2362#else
2363#define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd)
2364#endif
2365
2366int
2367sys_socket(int af, int type, int protocol)
2368{
2369 int fd;
2370 long s;
2371 child_process * cp;
2372
f249a012 2373 if (winsock_lib == NULL)
480b0c5b
GV
2374 {
2375 h_errno = ENETDOWN;
2376 return INVALID_SOCKET;
2377 }
2378
2379 check_errno ();
2380
2381 /* call the real socket function */
2382 s = (long) pfn_socket (af, type, protocol);
2383
2384 if (s != INVALID_SOCKET)
2385 {
2386 /* Although under NT 3.5 _open_osfhandle will accept a socket
2387 handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT,
2388 that does not work under NT 3.1. However, we can get the same
2389 effect by using a backdoor function to replace an existing
2390 descriptor handle with the one we want. */
2391
2392 /* allocate a file descriptor (with appropriate flags) */
2393 fd = _open ("NUL:", _O_RDWR);
2394 if (fd >= 0)
2395 {
2396#ifdef SOCK_REPLACE_HANDLE
2397 /* now replace handle to NUL with our socket handle */
2398 CloseHandle ((HANDLE) _get_osfhandle (fd));
2399 _free_osfhnd (fd);
2400 _set_osfhnd (fd, s);
2401 /* setmode (fd, _O_BINARY); */
2402#else
2403 /* Make a non-inheritable copy of the socket handle. */
2404 {
2405 HANDLE parent;
2406 HANDLE new_s = INVALID_HANDLE_VALUE;
2407
2408 parent = GetCurrentProcess ();
2409
f1614061
RS
2410 /* Apparently there is a bug in NT 3.51 with some service
2411 packs, which prevents using DuplicateHandle to make a
2412 socket handle non-inheritable (causes WSACleanup to
2413 hang). The work-around is to use SetHandleInformation
2414 instead if it is available and implemented. */
2415 if (!pfn_SetHandleInformation
2416 || !pfn_SetHandleInformation ((HANDLE) s,
2417 HANDLE_FLAG_INHERIT,
caf1a172 2418 0))
f1614061
RS
2419 {
2420 DuplicateHandle (parent,
2421 (HANDLE) s,
2422 parent,
2423 &new_s,
2424 0,
2425 FALSE,
2426 DUPLICATE_SAME_ACCESS);
2427 pfn_closesocket (s);
2428 s = (SOCKET) new_s;
2429 }
2430 fd_info[fd].hnd = (HANDLE) s;
480b0c5b
GV
2431 }
2432#endif
2433
2434 /* set our own internal flags */
2435 fd_info[fd].flags = FILE_SOCKET | FILE_BINARY | FILE_READ | FILE_WRITE;
2436
2437 cp = new_child ();
2438 if (cp)
2439 {
2440 cp->fd = fd;
2441 cp->status = STATUS_READ_ACKNOWLEDGED;
2442
2443 /* attach child_process to fd_info */
2444 if (fd_info[ fd ].cp != NULL)
2445 {
2446 DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd));
2447 abort ();
2448 }
2449
2450 fd_info[ fd ].cp = cp;
2451
2452 /* success! */
f249a012 2453 winsock_inuse++; /* count open sockets */
480b0c5b
GV
2454 return fd;
2455 }
2456
2457 /* clean up */
2458 _close (fd);
2459 }
2460 pfn_closesocket (s);
2461 h_errno = EMFILE;
2462 }
2463 set_errno ();
2464
2465 return -1;
2466}
2467
2468
2469int
2470sys_bind (int s, const struct sockaddr * addr, int namelen)
2471{
f249a012 2472 if (winsock_lib == NULL)
480b0c5b
GV
2473 {
2474 h_errno = ENOTSOCK;
2475 return SOCKET_ERROR;
2476 }
2477
2478 check_errno ();
2479 if (fd_info[s].flags & FILE_SOCKET)
2480 {
2481 int rc = pfn_bind (SOCK_HANDLE (s), addr, namelen);
2482 if (rc == SOCKET_ERROR)
2483 set_errno ();
2484 return rc;
2485 }
2486 h_errno = ENOTSOCK;
2487 return SOCKET_ERROR;
2488}
2489
2490
2491int
2492sys_connect (int s, const struct sockaddr * name, int namelen)
2493{
f249a012 2494 if (winsock_lib == NULL)
480b0c5b
GV
2495 {
2496 h_errno = ENOTSOCK;
2497 return SOCKET_ERROR;
2498 }
2499
2500 check_errno ();
2501 if (fd_info[s].flags & FILE_SOCKET)
2502 {
2503 int rc = pfn_connect (SOCK_HANDLE (s), name, namelen);
2504 if (rc == SOCKET_ERROR)
2505 set_errno ();
2506 return rc;
2507 }
2508 h_errno = ENOTSOCK;
2509 return SOCKET_ERROR;
2510}
2511
2512u_short
2513sys_htons (u_short hostshort)
2514{
f249a012 2515 return (winsock_lib != NULL) ?
480b0c5b
GV
2516 pfn_htons (hostshort) : hostshort;
2517}
2518
2519u_short
2520sys_ntohs (u_short netshort)
2521{
f249a012 2522 return (winsock_lib != NULL) ?
480b0c5b
GV
2523 pfn_ntohs (netshort) : netshort;
2524}
2525
2526unsigned long
2527sys_inet_addr (const char * cp)
2528{
f249a012 2529 return (winsock_lib != NULL) ?
480b0c5b
GV
2530 pfn_inet_addr (cp) : INADDR_NONE;
2531}
2532
2533int
2534sys_gethostname (char * name, int namelen)
2535{
f249a012 2536 if (winsock_lib != NULL)
480b0c5b
GV
2537 return pfn_gethostname (name, namelen);
2538
2539 if (namelen > MAX_COMPUTERNAME_LENGTH)
2540 return !GetComputerName (name, &namelen);
2541
2542 h_errno = EFAULT;
2543 return SOCKET_ERROR;
2544}
2545
2546struct hostent *
2547sys_gethostbyname(const char * name)
2548{
2549 struct hostent * host;
2550
f249a012 2551 if (winsock_lib == NULL)
480b0c5b
GV
2552 {
2553 h_errno = ENETDOWN;
2554 return NULL;
2555 }
2556
2557 check_errno ();
2558 host = pfn_gethostbyname (name);
2559 if (!host)
2560 set_errno ();
2561 return host;
2562}
2563
2564struct servent *
2565sys_getservbyname(const char * name, const char * proto)
2566{
2567 struct servent * serv;
2568
f249a012 2569 if (winsock_lib == NULL)
480b0c5b
GV
2570 {
2571 h_errno = ENETDOWN;
2572 return NULL;
2573 }
2574
2575 check_errno ();
2576 serv = pfn_getservbyname (name, proto);
2577 if (!serv)
2578 set_errno ();
2579 return serv;
2580}
2581
380961a6
GV
2582int
2583sys_shutdown (int s, int how)
2584{
2585 int rc;
2586
2587 if (winsock_lib == NULL)
2588 {
2589 h_errno = ENETDOWN;
2590 return SOCKET_ERROR;
2591 }
2592
2593 check_errno ();
2594 if (fd_info[s].flags & FILE_SOCKET)
2595 {
2596 int rc = pfn_shutdown (SOCK_HANDLE (s), how);
2597 if (rc == SOCKET_ERROR)
2598 set_errno ();
2599 return rc;
2600 }
2601 h_errno = ENOTSOCK;
2602 return SOCKET_ERROR;
2603}
2604
480b0c5b
GV
2605#endif /* HAVE_SOCKETS */
2606
2607
2608/* Shadow main io functions: we need to handle pipes and sockets more
2609 intelligently, and implement non-blocking mode as well. */
2610
2611int
2612sys_close (int fd)
2613{
2614 int rc;
2615
2616 if (fd < 0 || fd >= MAXDESC)
2617 {
2618 errno = EBADF;
2619 return -1;
2620 }
2621
2622 if (fd_info[fd].cp)
2623 {
2624 child_process * cp = fd_info[fd].cp;
2625
2626 fd_info[fd].cp = NULL;
2627
2628 if (CHILD_ACTIVE (cp))
2629 {
2630 /* if last descriptor to active child_process then cleanup */
2631 int i;
2632 for (i = 0; i < MAXDESC; i++)
2633 {
2634 if (i == fd)
2635 continue;
2636 if (fd_info[i].cp == cp)
2637 break;
2638 }
2639 if (i == MAXDESC)
2640 {
f249a012 2641#ifdef HAVE_SOCKETS
480b0c5b
GV
2642 if (fd_info[fd].flags & FILE_SOCKET)
2643 {
f249a012
RS
2644#ifndef SOCK_REPLACE_HANDLE
2645 if (winsock_lib == NULL) abort ();
480b0c5b
GV
2646
2647 pfn_shutdown (SOCK_HANDLE (fd), 2);
2648 rc = pfn_closesocket (SOCK_HANDLE (fd));
f249a012
RS
2649#endif
2650 winsock_inuse--; /* count open sockets */
480b0c5b
GV
2651 }
2652#endif
2653 delete_child (cp);
2654 }
2655 }
2656 }
2657
2658 /* Note that sockets do not need special treatment here (at least on
e9e23e23 2659 NT and Windows 95 using the standard tcp/ip stacks) - it appears that
480b0c5b
GV
2660 closesocket is equivalent to CloseHandle, which is to be expected
2661 because socket handles are fully fledged kernel handles. */
2662 rc = _close (fd);
2663
2664 if (rc == 0)
2665 fd_info[fd].flags = 0;
2666
2667 return rc;
2668}
2669
2670int
2671sys_dup (int fd)
2672{
2673 int new_fd;
2674
2675 new_fd = _dup (fd);
2676 if (new_fd >= 0)
2677 {
2678 /* duplicate our internal info as well */
2679 fd_info[new_fd] = fd_info[fd];
2680 }
2681 return new_fd;
2682}
2683
2684
2685int
2686sys_dup2 (int src, int dst)
2687{
2688 int rc;
2689
2690 if (dst < 0 || dst >= MAXDESC)
2691 {
2692 errno = EBADF;
2693 return -1;
2694 }
2695
2696 /* make sure we close the destination first if it's a pipe or socket */
2697 if (src != dst && fd_info[dst].flags != 0)
2698 sys_close (dst);
2699
2700 rc = _dup2 (src, dst);
2701 if (rc == 0)
2702 {
2703 /* duplicate our internal info as well */
2704 fd_info[dst] = fd_info[src];
2705 }
2706 return rc;
2707}
2708
480b0c5b
GV
2709/* Unix pipe() has only one arg */
2710int
2711sys_pipe (int * phandles)
2712{
2713 int rc;
2714 unsigned flags;
2715 child_process * cp;
2716
76b3903d
GV
2717 /* make pipe handles non-inheritable; when we spawn a child, we
2718 replace the relevant handle with an inheritable one. Also put
2719 pipes into binary mode; we will do text mode translation ourselves
2720 if required. */
2721 rc = _pipe (phandles, 0, _O_NOINHERIT | _O_BINARY);
480b0c5b
GV
2722
2723 if (rc == 0)
2724 {
7664e306 2725 flags = FILE_PIPE | FILE_READ | FILE_BINARY;
480b0c5b
GV
2726 fd_info[phandles[0]].flags = flags;
2727
7664e306 2728 flags = FILE_PIPE | FILE_WRITE | FILE_BINARY;
480b0c5b
GV
2729 fd_info[phandles[1]].flags = flags;
2730 }
2731
2732 return rc;
2733}
2734
f7554349 2735/* From ntproc.c */
fbd6baed 2736extern Lisp_Object Vw32_pipe_read_delay;
f7554349 2737
480b0c5b
GV
2738/* Function to do blocking read of one byte, needed to implement
2739 select. It is only allowed on sockets and pipes. */
2740int
2741_sys_read_ahead (int fd)
2742{
2743 child_process * cp;
2744 int rc;
2745
2746 if (fd < 0 || fd >= MAXDESC)
2747 return STATUS_READ_ERROR;
2748
2749 cp = fd_info[fd].cp;
2750
2751 if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
2752 return STATUS_READ_ERROR;
2753
2754 if ((fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET)) == 0
2755 || (fd_info[fd].flags & FILE_READ) == 0)
2756 {
2757 DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe or socket!\n", fd));
2758 abort ();
2759 }
2760
2761 cp->status = STATUS_READ_IN_PROGRESS;
2762
2763 if (fd_info[fd].flags & FILE_PIPE)
f7554349 2764 {
f7554349
KH
2765 rc = _read (fd, &cp->chr, sizeof (char));
2766
2767 /* Give subprocess time to buffer some more output for us before
e9e23e23 2768 reporting that input is available; we need this because Windows 95
f7554349
KH
2769 connects DOS programs to pipes by making the pipe appear to be
2770 the normal console stdout - as a result most DOS programs will
2771 write to stdout without buffering, ie. one character at a
fbd6baed 2772 time. Even some W32 programs do this - "dir" in a command
f7554349
KH
2773 shell on NT is very slow if we don't do this. */
2774 if (rc > 0)
2775 {
fbd6baed 2776 int wait = XINT (Vw32_pipe_read_delay);
f7554349
KH
2777
2778 if (wait > 0)
2779 Sleep (wait);
2780 else if (wait < 0)
2781 while (++wait <= 0)
2782 /* Yield remainder of our time slice, effectively giving a
2783 temporary priority boost to the child process. */
2784 Sleep (0);
2785 }
2786 }
480b0c5b
GV
2787#ifdef HAVE_SOCKETS
2788 else if (fd_info[fd].flags & FILE_SOCKET)
2789 rc = pfn_recv (SOCK_HANDLE (fd), &cp->chr, sizeof (char), 0);
2790#endif
2791
2792 if (rc == sizeof (char))
2793 cp->status = STATUS_READ_SUCCEEDED;
2794 else
2795 cp->status = STATUS_READ_FAILED;
2796
2797 return cp->status;
2798}
2799
2800int
2801sys_read (int fd, char * buffer, unsigned int count)
2802{
2803 int nchars;
480b0c5b
GV
2804 int to_read;
2805 DWORD waiting;
76b3903d 2806 char * orig_buffer = buffer;
480b0c5b
GV
2807
2808 if (fd < 0 || fd >= MAXDESC)
2809 {
2810 errno = EBADF;
2811 return -1;
2812 }
2813
2814 if (fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET))
2815 {
2816 child_process *cp = fd_info[fd].cp;
2817
2818 if ((fd_info[fd].flags & FILE_READ) == 0)
2819 {
2820 errno = EBADF;
2821 return -1;
2822 }
2823
76b3903d
GV
2824 nchars = 0;
2825
2826 /* re-read CR carried over from last read */
2827 if (fd_info[fd].flags & FILE_LAST_CR)
2828 {
2829 if (fd_info[fd].flags & FILE_BINARY) abort ();
2830 *buffer++ = 0x0d;
2831 count--;
2832 nchars++;
f52eb3ef 2833 fd_info[fd].flags &= ~FILE_LAST_CR;
76b3903d
GV
2834 }
2835
480b0c5b
GV
2836 /* presence of a child_process structure means we are operating in
2837 non-blocking mode - otherwise we just call _read directly.
2838 Note that the child_process structure might be missing because
2839 reap_subprocess has been called; in this case the pipe is
2840 already broken, so calling _read on it is okay. */
2841 if (cp)
2842 {
2843 int current_status = cp->status;
2844
2845 switch (current_status)
2846 {
2847 case STATUS_READ_FAILED:
2848 case STATUS_READ_ERROR:
f52eb3ef
GV
2849 /* report normal EOF if nothing in buffer */
2850 if (nchars <= 0)
2851 fd_info[fd].flags |= FILE_AT_EOF;
2852 return nchars;
480b0c5b
GV
2853
2854 case STATUS_READ_READY:
2855 case STATUS_READ_IN_PROGRESS:
2856 DebPrint (("sys_read called when read is in progress\n"));
2857 errno = EWOULDBLOCK;
2858 return -1;
2859
2860 case STATUS_READ_SUCCEEDED:
2861 /* consume read-ahead char */
2862 *buffer++ = cp->chr;
2863 count--;
76b3903d 2864 nchars++;
480b0c5b
GV
2865 cp->status = STATUS_READ_ACKNOWLEDGED;
2866 ResetEvent (cp->char_avail);
2867
2868 case STATUS_READ_ACKNOWLEDGED:
2869 break;
2870
2871 default:
2872 DebPrint (("sys_read: bad status %d\n", current_status));
2873 errno = EBADF;
2874 return -1;
2875 }
2876
2877 if (fd_info[fd].flags & FILE_PIPE)
2878 {
2879 PeekNamedPipe ((HANDLE) _get_osfhandle (fd), NULL, 0, NULL, &waiting, NULL);
2880 to_read = min (waiting, (DWORD) count);
f52eb3ef
GV
2881
2882 if (to_read > 0)
2883 nchars += _read (fd, buffer, to_read);
480b0c5b
GV
2884 }
2885#ifdef HAVE_SOCKETS
2886 else /* FILE_SOCKET */
2887 {
f249a012 2888 if (winsock_lib == NULL) abort ();
480b0c5b
GV
2889
2890 /* do the equivalent of a non-blocking read */
2891 pfn_ioctlsocket (SOCK_HANDLE (fd), FIONREAD, &waiting);
76b3903d 2892 if (waiting == 0 && nchars == 0)
480b0c5b
GV
2893 {
2894 h_errno = errno = EWOULDBLOCK;
2895 return -1;
2896 }
2897
480b0c5b
GV
2898 if (waiting)
2899 {
2900 /* always use binary mode for sockets */
76b3903d
GV
2901 int res = pfn_recv (SOCK_HANDLE (fd), buffer, count, 0);
2902 if (res == SOCKET_ERROR)
480b0c5b
GV
2903 {
2904 DebPrint(("sys_read.recv failed with error %d on socket %ld\n",
2905 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
76b3903d
GV
2906 set_errno ();
2907 return -1;
480b0c5b 2908 }
76b3903d 2909 nchars += res;
480b0c5b
GV
2910 }
2911 }
2912#endif
2913 }
2914 else
f52eb3ef
GV
2915 {
2916 int nread = _read (fd, buffer, count);
2917 if (nread >= 0)
2918 nchars += nread;
2919 else if (nchars == 0)
2920 nchars = nread;
2921 }
76b3903d 2922
f52eb3ef
GV
2923 if (nchars <= 0)
2924 fd_info[fd].flags |= FILE_AT_EOF;
76b3903d 2925 /* Perform text mode translation if required. */
f52eb3ef 2926 else if ((fd_info[fd].flags & FILE_BINARY) == 0)
76b3903d
GV
2927 {
2928 nchars = crlf_to_lf (nchars, orig_buffer);
2929 /* If buffer contains only CR, return that. To be absolutely
2930 sure we should attempt to read the next char, but in
2931 practice a CR to be followed by LF would not appear by
2932 itself in the buffer. */
2933 if (nchars > 1 && orig_buffer[nchars - 1] == 0x0d)
2934 {
2935 fd_info[fd].flags |= FILE_LAST_CR;
2936 nchars--;
2937 }
76b3903d 2938 }
480b0c5b
GV
2939 }
2940 else
2941 nchars = _read (fd, buffer, count);
2942
76b3903d 2943 return nchars;
480b0c5b
GV
2944}
2945
2946/* For now, don't bother with a non-blocking mode */
2947int
2948sys_write (int fd, const void * buffer, unsigned int count)
2949{
2950 int nchars;
2951
2952 if (fd < 0 || fd >= MAXDESC)
2953 {
2954 errno = EBADF;
2955 return -1;
2956 }
2957
2958 if (fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET))
76b3903d
GV
2959 {
2960 if ((fd_info[fd].flags & FILE_WRITE) == 0)
2961 {
2962 errno = EBADF;
2963 return -1;
2964 }
2965
2966 /* Perform text mode translation if required. */
2967 if ((fd_info[fd].flags & FILE_BINARY) == 0)
2968 {
2969 char * tmpbuf = alloca (count * 2);
2970 unsigned char * src = (void *)buffer;
2971 unsigned char * dst = tmpbuf;
2972 int nbytes = count;
2973
2974 while (1)
2975 {
2976 unsigned char *next;
2977 /* copy next line or remaining bytes */
2978 next = _memccpy (dst, src, '\n', nbytes);
2979 if (next)
2980 {
2981 /* copied one line ending with '\n' */
2982 int copied = next - dst;
2983 nbytes -= copied;
2984 src += copied;
2985 /* insert '\r' before '\n' */
2986 next[-1] = '\r';
2987 next[0] = '\n';
2988 dst = next + 1;
2989 count++;
2990 }
2991 else
2992 /* copied remaining partial line -> now finished */
2993 break;
2994 }
2995 buffer = tmpbuf;
2996 }
2997 }
2998
480b0c5b
GV
2999#ifdef HAVE_SOCKETS
3000 if (fd_info[fd].flags & FILE_SOCKET)
3001 {
f249a012 3002 if (winsock_lib == NULL) abort ();
480b0c5b
GV
3003 nchars = pfn_send (SOCK_HANDLE (fd), buffer, count, 0);
3004 if (nchars == SOCKET_ERROR)
3005 {
3006 DebPrint(("sys_read.send failed with error %d on socket %ld\n",
3007 pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
3008 set_errno ();
3009 }
3010 }
3011 else
3012#endif
3013 nchars = _write (fd, buffer, count);
3014
3015 return nchars;
3016}
3017
f52eb3ef
GV
3018static void
3019check_windows_init_file ()
3020{
3021 extern int noninteractive, inhibit_window_system;
3022
3023 /* A common indication that Emacs is not installed properly is when
3024 it cannot find the Windows installation file. If this file does
3025 not exist in the expected place, tell the user. */
3026
d54abccd
GV
3027 if (!noninteractive && !inhibit_window_system)
3028 {
3029 extern Lisp_Object Vwindow_system, Vload_path, Qfile_exists_p;
96ef7d42 3030 Lisp_Object full_load_path;
d54abccd
GV
3031 Lisp_Object init_file;
3032 int fd;
f52eb3ef 3033
d54abccd 3034 init_file = build_string ("term/w32-win");
96ef7d42
GV
3035 full_load_path = Fcons (build_string (getenv ("EMACSLOADPATH")),
3036 Vload_path);
3037 fd = openp (full_load_path, init_file, ".el:.elc", NULL, 0);
d54abccd
GV
3038 if (fd < 0)
3039 {
96ef7d42 3040 Lisp_Object load_path_print = Fprin1_to_string (full_load_path, Qnil);
d54abccd
GV
3041 char *init_file_name = XSTRING (init_file)->data;
3042 char *load_path = XSTRING (load_path_print)->data;
3043 char *buffer = alloca (1024);
3044
3045 sprintf (buffer,
3046 "The Emacs Windows initialization file \"%s.el\" "
3047 "could not be found in your Emacs installation. "
3048 "Emacs checked the following directories for this file:\n"
3049 "\n%s\n\n"
3050 "When Emacs cannot find this file, it usually means that it "
3051 "was not installed properly, or its distribution file was "
3052 "not unpacked properly.\nSee the README.W32 file in the "
3053 "top-level Emacs directory for more information.",
3054 init_file_name, load_path);
3055 MessageBox (NULL,
3056 buffer,
3057 "Emacs Abort Dialog",
3058 MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
f52eb3ef
GV
3059 /* Use the low-level Emacs abort. */
3060#undef abort
d54abccd
GV
3061 abort ();
3062 }
3063 else
3064 {
3065 close (fd);
3066 }
f52eb3ef 3067 }
f52eb3ef 3068}
480b0c5b
GV
3069
3070void
3071term_ntproc ()
3072{
3073#ifdef HAVE_SOCKETS
3074 /* shutdown the socket interface if necessary */
3075 term_winsock ();
3076#endif
3077}
3078
3079void
3080init_ntproc ()
3081{
3082#ifdef HAVE_SOCKETS
f249a012
RS
3083 /* Initialise the socket interface now if available and requested by
3084 the user by defining PRELOAD_WINSOCK; otherwise loading will be
fbd6baed 3085 delayed until open-network-stream is called (w32-has-winsock can
f249a012
RS
3086 also be used to dynamically load or reload winsock).
3087
3088 Conveniently, init_environment is called before us, so
3089 PRELOAD_WINSOCK can be set in the registry. */
3090
3091 /* Always initialize this correctly. */
3092 winsock_lib = NULL;
3093
3094 if (getenv ("PRELOAD_WINSOCK") != NULL)
3095 init_winsock (TRUE);
480b0c5b
GV
3096#endif
3097
3098 /* Initial preparation for subprocess support: replace our standard
3099 handles with non-inheritable versions. */
3100 {
3101 HANDLE parent;
3102 HANDLE stdin_save = INVALID_HANDLE_VALUE;
3103 HANDLE stdout_save = INVALID_HANDLE_VALUE;
3104 HANDLE stderr_save = INVALID_HANDLE_VALUE;
3105
3106 parent = GetCurrentProcess ();
3107
3108 /* ignore errors when duplicating and closing; typically the
3109 handles will be invalid when running as a gui program. */
3110 DuplicateHandle (parent,
3111 GetStdHandle (STD_INPUT_HANDLE),
3112 parent,
3113 &stdin_save,
3114 0,
3115 FALSE,
3116 DUPLICATE_SAME_ACCESS);
3117
3118 DuplicateHandle (parent,
3119 GetStdHandle (STD_OUTPUT_HANDLE),
3120 parent,
3121 &stdout_save,
3122 0,
3123 FALSE,
3124 DUPLICATE_SAME_ACCESS);
3125
3126 DuplicateHandle (parent,
3127 GetStdHandle (STD_ERROR_HANDLE),
3128 parent,
3129 &stderr_save,
3130 0,
3131 FALSE,
3132 DUPLICATE_SAME_ACCESS);
3133
3134 fclose (stdin);
3135 fclose (stdout);
3136 fclose (stderr);
3137
3138 if (stdin_save != INVALID_HANDLE_VALUE)
3139 _open_osfhandle ((long) stdin_save, O_TEXT);
3140 else
76b3903d
GV
3141 _open ("nul", O_TEXT | O_NOINHERIT | O_RDONLY);
3142 _fdopen (0, "r");
480b0c5b
GV
3143
3144 if (stdout_save != INVALID_HANDLE_VALUE)
3145 _open_osfhandle ((long) stdout_save, O_TEXT);
3146 else
76b3903d
GV
3147 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
3148 _fdopen (1, "w");
480b0c5b
GV
3149
3150 if (stderr_save != INVALID_HANDLE_VALUE)
3151 _open_osfhandle ((long) stderr_save, O_TEXT);
3152 else
76b3903d
GV
3153 _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
3154 _fdopen (2, "w");
480b0c5b
GV
3155 }
3156
3157 /* unfortunately, atexit depends on implementation of malloc */
3158 /* atexit (term_ntproc); */
3159 signal (SIGABRT, term_ntproc);
76b3903d
GV
3160
3161 /* determine which drives are fixed, for GetCachedVolumeInformation */
3162 {
3163 /* GetDriveType must have trailing backslash. */
3164 char drive[] = "A:\\";
3165
3166 /* Loop over all possible drive letters */
3167 while (*drive <= 'Z')
3168 {
3169 /* Record if this drive letter refers to a fixed drive. */
3170 fixed_drives[DRIVE_INDEX (*drive)] =
3171 (GetDriveType (drive) == DRIVE_FIXED);
3172
3173 (*drive)++;
3174 }
3175 }
d54abccd
GV
3176
3177 /* Check to see if Emacs has been installed correctly. */
3178 check_windows_init_file ();
480b0c5b
GV
3179}
3180
3181/* end of nt.c */