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