diff options
| author | Geoff Voelker | 1997-09-03 00:43:20 +0000 |
|---|---|---|
| committer | Geoff Voelker | 1997-09-03 00:43:20 +0000 |
| commit | 76b3903d852a0c33964da1e73a7d8e152ef8189a (patch) | |
| tree | f637f4ec058446fb60a54fe4f3574630d28e2215 /src | |
| parent | 43640c4dfeec138b7c789f998062e94e7d61303b (diff) | |
| download | emacs-76b3903d852a0c33964da1e73a7d8e152ef8189a.tar.gz emacs-76b3903d852a0c33964da1e73a7d8e152ef8189a.zip | |
Include stddef.h.
(getwd): Delete macro.
(startup_dir): New variable.
(getwd): Return directory in which Emacs started.
(init_user_info): Set SHELL environment variable if not set.
(parse_root, get_long_basename, w32_get_long_filename): New functions.
(init_environment): Look for CMDPROXY.
Make sure that PATH and COMSPEC are capitalized in the environment.
Record startup directory.
(get_emacs_configuration, sys_rename): Use OS_WIN95.
(map_w32_filename): Calculate returned string correctly.
(sys_fopen): Use _fdopen.
(sys_link): Support NTFS links.
(sys_rename): Use a long file name for temporary name.
(sys_pipe): Make pipes binary and non-inheritable.
(sys_read, sys_write): Spoof text mode translation for pipes
and sockets.
(hashval): Simplify.
(generate_inode_val): Use long file name version of file.
(stat): Optimize by using active readdir info.
Set fake_inode to 0 for directories.
Set fake_inode to xor of file indexes for files.
Don't use generate_inode_val to set inode value.
(volume_info_data): Renamed from volume_info.
(volume_info, fixed_drives, volume_cache): New variables.
(DRIVE_INDEX, VOLINFO_STILL_VALID): New macros.
(lookup_volume_info, add_volume_info, GetCachedVolumeInformation):
New functions.
(get_volume_info): Use volume_info_data.
Use GetCachedVolumeInformation.
(init_ntproc): No longer restrict to one DOS subprocess.
Use CRT _open and _fdopen.
Cache fixed drive information.
Diffstat (limited to 'src')
| -rw-r--r-- | src/w32.c | 923 |
1 files changed, 690 insertions, 233 deletions
| @@ -22,6 +22,7 @@ Boston, MA 02111-1307, USA. | |||
| 22 | */ | 22 | */ |
| 23 | 23 | ||
| 24 | 24 | ||
| 25 | #include <stddef.h> /* for offsetof */ | ||
| 25 | #include <stdlib.h> | 26 | #include <stdlib.h> |
| 26 | #include <stdio.h> | 27 | #include <stdio.h> |
| 27 | #include <io.h> | 28 | #include <io.h> |
| @@ -54,9 +55,7 @@ Boston, MA 02111-1307, USA. | |||
| 54 | #undef read | 55 | #undef read |
| 55 | #undef write | 56 | #undef write |
| 56 | 57 | ||
| 57 | #define getwd _getwd | ||
| 58 | #include "lisp.h" | 58 | #include "lisp.h" |
| 59 | #undef getwd | ||
| 60 | 59 | ||
| 61 | #include <pwd.h> | 60 | #include <pwd.h> |
| 62 | 61 | ||
| @@ -79,14 +78,28 @@ Boston, MA 02111-1307, USA. | |||
| 79 | #include "w32.h" | 78 | #include "w32.h" |
| 80 | #include "ndir.h" | 79 | #include "ndir.h" |
| 81 | #include "w32heap.h" | 80 | #include "w32heap.h" |
| 81 | |||
| 82 | extern Lisp_Object Vw32_downcase_file_names; | ||
| 83 | extern Lisp_Object Vw32_generate_fake_inodes; | ||
| 84 | extern Lisp_Object Vw32_get_true_file_attributes; | ||
| 85 | |||
| 86 | static char startup_dir[MAXPATHLEN]; | ||
| 82 | 87 | ||
| 83 | /* Get the current working directory. */ | 88 | /* Get the current working directory. */ |
| 84 | char * | 89 | char * |
| 85 | getwd (char *dir) | 90 | getwd (char *dir) |
| 86 | { | 91 | { |
| 92 | #if 0 | ||
| 87 | if (GetCurrentDirectory (MAXPATHLEN, dir) > 0) | 93 | if (GetCurrentDirectory (MAXPATHLEN, dir) > 0) |
| 88 | return dir; | 94 | return dir; |
| 89 | return NULL; | 95 | return NULL; |
| 96 | #else | ||
| 97 | /* Emacs doesn't actually change directory itself, and we want to | ||
| 98 | force our real wd to be where emacs.exe is to avoid unnecessary | ||
| 99 | conflicts when trying to rename or delete directories. */ | ||
| 100 | strcpy (dir, startup_dir); | ||
| 101 | return dir; | ||
| 102 | #endif | ||
| 90 | } | 103 | } |
| 91 | 104 | ||
| 92 | #ifndef HAVE_SOCKETS | 105 | #ifndef HAVE_SOCKETS |
| @@ -114,105 +127,6 @@ getloadavg (double loadavg[], int nelem) | |||
| 114 | return i; | 127 | return i; |
| 115 | } | 128 | } |
| 116 | 129 | ||
| 117 | /* Emulate the Unix directory procedures opendir, closedir, | ||
| 118 | and readdir. We can't use the procedures supplied in sysdep.c, | ||
| 119 | so we provide them here. */ | ||
| 120 | |||
| 121 | struct direct dir_static; /* simulated directory contents */ | ||
| 122 | static HANDLE dir_find_handle = INVALID_HANDLE_VALUE; | ||
| 123 | static int dir_is_fat; | ||
| 124 | static char dir_pathname[MAXPATHLEN+1]; | ||
| 125 | |||
| 126 | extern Lisp_Object Vw32_downcase_file_names; | ||
| 127 | |||
| 128 | DIR * | ||
| 129 | opendir (char *filename) | ||
| 130 | { | ||
| 131 | DIR *dirp; | ||
| 132 | |||
| 133 | /* Opening is done by FindFirstFile. However, a read is inherent to | ||
| 134 | this operation, so we defer the open until read time. */ | ||
| 135 | |||
| 136 | if (!(dirp = (DIR *) malloc (sizeof (DIR)))) | ||
| 137 | return NULL; | ||
| 138 | if (dir_find_handle != INVALID_HANDLE_VALUE) | ||
| 139 | return NULL; | ||
| 140 | |||
| 141 | dirp->dd_fd = 0; | ||
| 142 | dirp->dd_loc = 0; | ||
| 143 | dirp->dd_size = 0; | ||
| 144 | |||
| 145 | strncpy (dir_pathname, filename, MAXPATHLEN); | ||
| 146 | dir_pathname[MAXPATHLEN] = '\0'; | ||
| 147 | dir_is_fat = is_fat_volume (filename, NULL); | ||
| 148 | |||
| 149 | return dirp; | ||
| 150 | } | ||
| 151 | |||
| 152 | void | ||
| 153 | closedir (DIR *dirp) | ||
| 154 | { | ||
| 155 | /* If we have a find-handle open, close it. */ | ||
| 156 | if (dir_find_handle != INVALID_HANDLE_VALUE) | ||
| 157 | { | ||
| 158 | FindClose (dir_find_handle); | ||
| 159 | dir_find_handle = INVALID_HANDLE_VALUE; | ||
| 160 | } | ||
| 161 | xfree ((char *) dirp); | ||
| 162 | } | ||
| 163 | |||
| 164 | struct direct * | ||
| 165 | readdir (DIR *dirp) | ||
| 166 | { | ||
| 167 | WIN32_FIND_DATA find_data; | ||
| 168 | |||
| 169 | /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */ | ||
| 170 | if (dir_find_handle == INVALID_HANDLE_VALUE) | ||
| 171 | { | ||
| 172 | char filename[MAXNAMLEN + 3]; | ||
| 173 | int ln; | ||
| 174 | |||
| 175 | strcpy (filename, dir_pathname); | ||
| 176 | ln = strlen (filename) - 1; | ||
| 177 | if (!IS_DIRECTORY_SEP (filename[ln])) | ||
| 178 | strcat (filename, "\\"); | ||
| 179 | strcat (filename, "*"); | ||
| 180 | |||
| 181 | dir_find_handle = FindFirstFile (filename, &find_data); | ||
| 182 | |||
| 183 | if (dir_find_handle == INVALID_HANDLE_VALUE) | ||
| 184 | return NULL; | ||
| 185 | } | ||
| 186 | else | ||
| 187 | { | ||
| 188 | if (!FindNextFile (dir_find_handle, &find_data)) | ||
| 189 | return NULL; | ||
| 190 | } | ||
| 191 | |||
| 192 | /* Emacs never uses this value, so don't bother making it match | ||
| 193 | value returned by stat(). */ | ||
| 194 | dir_static.d_ino = 1; | ||
| 195 | |||
| 196 | dir_static.d_reclen = sizeof (struct direct) - MAXNAMLEN + 3 + | ||
| 197 | dir_static.d_namlen - dir_static.d_namlen % 4; | ||
| 198 | |||
| 199 | dir_static.d_namlen = strlen (find_data.cFileName); | ||
| 200 | strcpy (dir_static.d_name, find_data.cFileName); | ||
| 201 | if (dir_is_fat) | ||
| 202 | _strlwr (dir_static.d_name); | ||
| 203 | else if (!NILP (Vw32_downcase_file_names)) | ||
| 204 | { | ||
| 205 | register char *p; | ||
| 206 | for (p = dir_static.d_name; *p; p++) | ||
| 207 | if (*p >= 'a' && *p <= 'z') | ||
| 208 | break; | ||
| 209 | if (!*p) | ||
| 210 | _strlwr (dir_static.d_name); | ||
| 211 | } | ||
| 212 | |||
| 213 | return &dir_static; | ||
| 214 | } | ||
| 215 | |||
| 216 | /* Emulate getpwuid, getpwnam and others. */ | 130 | /* Emulate getpwuid, getpwnam and others. */ |
| 217 | 131 | ||
| 218 | #define PASSWD_FIELD_SIZE 256 | 132 | #define PASSWD_FIELD_SIZE 256 |
| @@ -367,7 +281,7 @@ init_user_info () | |||
| 367 | if (getenv ("HOME") == NULL) | 281 | if (getenv ("HOME") == NULL) |
| 368 | putenv ("HOME=c:/"); | 282 | putenv ("HOME=c:/"); |
| 369 | if (getenv ("SHELL") == NULL) | 283 | if (getenv ("SHELL") == NULL) |
| 370 | putenv ((GetVersion () & 0x80000000) ? "SHELL=command" : "SHELL=cmd"); | 284 | putenv (os_subtype == OS_WIN95 ? "SHELL=command" : "SHELL=cmd"); |
| 371 | 285 | ||
| 372 | /* Set dir and shell from environment variables. */ | 286 | /* Set dir and shell from environment variables. */ |
| 373 | strcpy (the_passwd.pw_dir, getenv ("HOME")); | 287 | strcpy (the_passwd.pw_dir, getenv ("HOME")); |
| @@ -390,6 +304,7 @@ srandom (int seed) | |||
| 390 | srand (seed); | 304 | srand (seed); |
| 391 | } | 305 | } |
| 392 | 306 | ||
| 307 | |||
| 393 | /* Normalize filename by converting all path separators to | 308 | /* Normalize filename by converting all path separators to |
| 394 | the specified separator. Also conditionally convert upper | 309 | the specified separator. Also conditionally convert upper |
| 395 | case path name components to lower case. */ | 310 | case path name components to lower case. */ |
| @@ -496,6 +411,118 @@ crlf_to_lf (n, buf) | |||
| 496 | return np - startp; | 411 | return np - startp; |
| 497 | } | 412 | } |
| 498 | 413 | ||
| 414 | /* Parse the root part of file name, if present. Return length and | ||
| 415 | optionally store pointer to char after root. */ | ||
| 416 | static int | ||
| 417 | parse_root (char * name, char ** pPath) | ||
| 418 | { | ||
| 419 | char * start = name; | ||
| 420 | |||
| 421 | if (name == NULL) | ||
| 422 | return 0; | ||
| 423 | |||
| 424 | /* find the root name of the volume if given */ | ||
| 425 | if (isalpha (name[0]) && name[1] == ':') | ||
| 426 | { | ||
| 427 | /* skip past drive specifier */ | ||
| 428 | name += 2; | ||
| 429 | if (IS_DIRECTORY_SEP (name[0])) | ||
| 430 | name++; | ||
| 431 | } | ||
| 432 | else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1])) | ||
| 433 | { | ||
| 434 | int slashes = 2; | ||
| 435 | name += 2; | ||
| 436 | do | ||
| 437 | { | ||
| 438 | if (IS_DIRECTORY_SEP (*name) && --slashes == 0) | ||
| 439 | break; | ||
| 440 | name++; | ||
| 441 | } | ||
| 442 | while ( *name ); | ||
| 443 | if (IS_DIRECTORY_SEP (name[0])) | ||
| 444 | name++; | ||
| 445 | } | ||
| 446 | |||
| 447 | if (pPath) | ||
| 448 | *pPath = name; | ||
| 449 | |||
| 450 | return name - start; | ||
| 451 | } | ||
| 452 | |||
| 453 | /* Get long base name for name; name is assumed to be absolute. */ | ||
| 454 | static int | ||
| 455 | get_long_basename (char * name, char * buf, int size) | ||
| 456 | { | ||
| 457 | WIN32_FIND_DATA find_data; | ||
| 458 | HANDLE dir_handle; | ||
| 459 | int len = 0; | ||
| 460 | |||
| 461 | dir_handle = FindFirstFile (name, &find_data); | ||
| 462 | if (dir_handle != INVALID_HANDLE_VALUE) | ||
| 463 | { | ||
| 464 | if ((len = strlen (find_data.cFileName)) < size) | ||
| 465 | memcpy (buf, find_data.cFileName, len + 1); | ||
| 466 | else | ||
| 467 | len = 0; | ||
| 468 | FindClose (dir_handle); | ||
| 469 | } | ||
| 470 | return len; | ||
| 471 | } | ||
| 472 | |||
| 473 | /* Get long name for file, if possible (assumed to be absolute). */ | ||
| 474 | BOOL | ||
| 475 | w32_get_long_filename (char * name, char * buf, int size) | ||
| 476 | { | ||
| 477 | char * o = buf; | ||
| 478 | char * p; | ||
| 479 | char * q; | ||
| 480 | char full[ MAX_PATH ]; | ||
| 481 | int len; | ||
| 482 | |||
| 483 | len = strlen (name); | ||
| 484 | if (len >= MAX_PATH) | ||
| 485 | return FALSE; | ||
| 486 | |||
| 487 | /* Use local copy for destructive modification. */ | ||
| 488 | memcpy (full, name, len+1); | ||
| 489 | unixtodos_filename (full); | ||
| 490 | |||
| 491 | /* Copy root part verbatim. */ | ||
| 492 | len = parse_root (full, &p); | ||
| 493 | memcpy (o, full, len); | ||
| 494 | o += len; | ||
| 495 | size -= len; | ||
| 496 | |||
| 497 | do | ||
| 498 | { | ||
| 499 | q = p; | ||
| 500 | p = strchr (q, '\\'); | ||
| 501 | if (p) *p = '\0'; | ||
| 502 | len = get_long_basename (full, o, size); | ||
| 503 | if (len > 0) | ||
| 504 | { | ||
| 505 | o += len; | ||
| 506 | size -= len; | ||
| 507 | if (p != NULL) | ||
| 508 | { | ||
| 509 | *p++ = '\\'; | ||
| 510 | if (size < 2) | ||
| 511 | return FALSE; | ||
| 512 | *o++ = '\\'; | ||
| 513 | size--; | ||
| 514 | *o = '\0'; | ||
| 515 | } | ||
| 516 | } | ||
| 517 | else | ||
| 518 | return FALSE; | ||
| 519 | } | ||
| 520 | while (p != NULL && *p); | ||
| 521 | |||
| 522 | return TRUE; | ||
| 523 | } | ||
| 524 | |||
| 525 | |||
| 499 | /* Routines that are no-ops on NT but are defined to get Emacs to compile. */ | 526 | /* Routines that are no-ops on NT but are defined to get Emacs to compile. */ |
| 500 | 527 | ||
| 501 | int | 528 | int |
| @@ -569,9 +596,9 @@ w32_get_resource (key, lpdwtype) | |||
| 569 | { | 596 | { |
| 570 | lpvalue = NULL; | 597 | lpvalue = NULL; |
| 571 | 598 | ||
| 572 | if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS && | 599 | if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS |
| 573 | (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL && | 600 | && (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL |
| 574 | RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS) | 601 | && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS) |
| 575 | { | 602 | { |
| 576 | return (lpvalue); | 603 | return (lpvalue); |
| 577 | } | 604 | } |
| @@ -603,18 +630,21 @@ init_environment () | |||
| 603 | "emacs_dir", | 630 | "emacs_dir", |
| 604 | "EMACSLOADPATH", | 631 | "EMACSLOADPATH", |
| 605 | "SHELL", | 632 | "SHELL", |
| 633 | "CMDPROXY", | ||
| 606 | "EMACSDATA", | 634 | "EMACSDATA", |
| 607 | "EMACSPATH", | 635 | "EMACSPATH", |
| 608 | "EMACSLOCKDIR", | 636 | "EMACSLOCKDIR", |
| 609 | "INFOPATH", | 637 | /* We no longer set INFOPATH because Info-default-directory-list |
| 638 | is then ignored. We use a hook in winnt.el instead. */ | ||
| 639 | /* "INFOPATH", */ | ||
| 610 | "EMACSDOC", | 640 | "EMACSDOC", |
| 611 | "TERM", | 641 | "TERM", |
| 612 | }; | 642 | }; |
| 613 | 643 | ||
| 614 | for (i = 0; i < (sizeof (env_vars) / sizeof (env_vars[0])); i++) | 644 | for (i = 0; i < (sizeof (env_vars) / sizeof (env_vars[0])); i++) |
| 615 | { | 645 | { |
| 616 | if (!getenv (env_vars[i]) && | 646 | if (!getenv (env_vars[i]) |
| 617 | (lpval = w32_get_resource (env_vars[i], &dwType)) != NULL) | 647 | && (lpval = w32_get_resource (env_vars[i], &dwType)) != NULL) |
| 618 | { | 648 | { |
| 619 | if (dwType == REG_EXPAND_SZ) | 649 | if (dwType == REG_EXPAND_SZ) |
| 620 | { | 650 | { |
| @@ -640,6 +670,45 @@ init_environment () | |||
| 640 | /* Rebuild system configuration to reflect invoking system. */ | 670 | /* Rebuild system configuration to reflect invoking system. */ |
| 641 | Vsystem_configuration = build_string (EMACS_CONFIGURATION); | 671 | Vsystem_configuration = build_string (EMACS_CONFIGURATION); |
| 642 | 672 | ||
| 673 | /* Another special case: on NT, the PATH variable is actually named | ||
| 674 | "Path" although cmd.exe (perhaps NT itself) arranges for | ||
| 675 | environment variable lookup and setting to be case insensitive. | ||
| 676 | However, Emacs assumes a fully case sensitive environment, so we | ||
| 677 | need to change "Path" to "PATH" to match the expectations of | ||
| 678 | various elisp packages. We do this by the sneaky method of | ||
| 679 | modifying the string in the C runtime environ entry. | ||
| 680 | |||
| 681 | The same applies to COMSPEC. */ | ||
| 682 | { | ||
| 683 | char ** envp; | ||
| 684 | |||
| 685 | for (envp = environ; *envp; envp++) | ||
| 686 | if (_strnicmp (*envp, "PATH=", 5) == 0) | ||
| 687 | memcpy (*envp, "PATH=", 5); | ||
| 688 | else if (_strnicmp (*envp, "COMSPEC=", 8) == 0) | ||
| 689 | memcpy (*envp, "COMSPEC=", 8); | ||
| 690 | } | ||
| 691 | |||
| 692 | /* Remember the initial working directory for getwd, then make the | ||
| 693 | real wd be the location of emacs.exe to avoid conflicts when | ||
| 694 | renaming or deleting directories. (We also don't call chdir when | ||
| 695 | running subprocesses for the same reason.) */ | ||
| 696 | if (!GetCurrentDirectory (MAXPATHLEN, startup_dir)) | ||
| 697 | abort (); | ||
| 698 | |||
| 699 | { | ||
| 700 | char *p; | ||
| 701 | char modname[MAX_PATH]; | ||
| 702 | |||
| 703 | if (!GetModuleFileName (NULL, modname, MAX_PATH)) | ||
| 704 | abort (); | ||
| 705 | if ((p = strrchr (modname, '\\')) == NULL) | ||
| 706 | abort (); | ||
| 707 | *p = 0; | ||
| 708 | |||
| 709 | SetCurrentDirectory (modname); | ||
| 710 | } | ||
| 711 | |||
| 643 | init_user_info (); | 712 | init_user_info (); |
| 644 | } | 713 | } |
| 645 | 714 | ||
| @@ -695,7 +764,7 @@ get_emacs_configuration (void) | |||
| 695 | /* Let oem be "*" until we figure out how to decode the OEM field. */ | 764 | /* Let oem be "*" until we figure out how to decode the OEM field. */ |
| 696 | oem = "*"; | 765 | oem = "*"; |
| 697 | 766 | ||
| 698 | os = (GetVersion () & 0x80000000) ? "windows95" : "nt"; | 767 | os = (GetVersion () & OS_WIN95) ? "windows95" : "nt"; |
| 699 | 768 | ||
| 700 | sprintf (configuration_buffer, "%s-%s-%s%d.%d", arch, oem, os, | 769 | sprintf (configuration_buffer, "%s-%s-%s%d.%d", arch, oem, os, |
| 701 | get_w32_major_version (), get_w32_minor_version ()); | 770 | get_w32_major_version (), get_w32_minor_version ()); |
| @@ -743,23 +812,159 @@ sys_sleep (int seconds) | |||
| 743 | Sleep (seconds * 1000); | 812 | Sleep (seconds * 1000); |
| 744 | } | 813 | } |
| 745 | 814 | ||
| 746 | /* Internal MSVC data and functions for low-level descriptor munging */ | 815 | /* Internal MSVC functions for low-level descriptor munging */ |
| 747 | #if (_MSC_VER == 900) | ||
| 748 | extern char _osfile[]; | ||
| 749 | #endif | ||
| 750 | extern int __cdecl _set_osfhnd (int fd, long h); | 816 | extern int __cdecl _set_osfhnd (int fd, long h); |
| 751 | extern int __cdecl _free_osfhnd (int fd); | 817 | extern int __cdecl _free_osfhnd (int fd); |
| 752 | 818 | ||
| 753 | /* parallel array of private info on file handles */ | 819 | /* parallel array of private info on file handles */ |
| 754 | filedesc fd_info [ MAXDESC ]; | 820 | filedesc fd_info [ MAXDESC ]; |
| 755 | 821 | ||
| 756 | static struct { | 822 | typedef struct volume_info_data { |
| 823 | struct volume_info_data * next; | ||
| 824 | |||
| 825 | /* time when info was obtained */ | ||
| 826 | DWORD timestamp; | ||
| 827 | |||
| 828 | /* actual volume info */ | ||
| 829 | char * root_dir; | ||
| 757 | DWORD serialnum; | 830 | DWORD serialnum; |
| 758 | DWORD maxcomp; | 831 | DWORD maxcomp; |
| 759 | DWORD flags; | 832 | DWORD flags; |
| 760 | char name[32]; | 833 | char * name; |
| 761 | char type[32]; | 834 | char * type; |
| 762 | } volume_info; | 835 | } volume_info_data; |
| 836 | |||
| 837 | /* Global referenced by various functions. */ | ||
| 838 | static volume_info_data volume_info; | ||
| 839 | |||
| 840 | /* Vector to indicate which drives are local and fixed (for which cached | ||
| 841 | data never expires). */ | ||
| 842 | static BOOL fixed_drives[26]; | ||
| 843 | |||
| 844 | /* Consider cached volume information to be stale if older than 10s, | ||
| 845 | at least for non-local drives. Info for fixed drives is never stale. */ | ||
| 846 | #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' ) | ||
| 847 | #define VOLINFO_STILL_VALID( root_dir, info ) \ | ||
| 848 | ( ( isalpha (root_dir[0]) && \ | ||
| 849 | fixed_drives[ DRIVE_INDEX (root_dir[0]) ] ) \ | ||
| 850 | || GetTickCount () - info->timestamp < 10000 ) | ||
| 851 | |||
| 852 | /* Cache support functions. */ | ||
| 853 | |||
| 854 | /* Simple linked list with linear search is sufficient. */ | ||
| 855 | static volume_info_data *volume_cache = NULL; | ||
| 856 | |||
| 857 | static volume_info_data * | ||
| 858 | lookup_volume_info (char * root_dir) | ||
| 859 | { | ||
| 860 | volume_info_data * info; | ||
| 861 | |||
| 862 | for (info = volume_cache; info; info = info->next) | ||
| 863 | if (stricmp (info->root_dir, root_dir) == 0) | ||
| 864 | break; | ||
| 865 | return info; | ||
| 866 | } | ||
| 867 | |||
| 868 | static void | ||
| 869 | add_volume_info (char * root_dir, volume_info_data * info) | ||
| 870 | { | ||
| 871 | info->root_dir = strdup (root_dir); | ||
| 872 | info->next = volume_cache; | ||
| 873 | volume_cache = info; | ||
| 874 | } | ||
| 875 | |||
| 876 | |||
| 877 | /* Wrapper for GetVolumeInformation, which uses caching to avoid | ||
| 878 | performance penalty (~2ms on 486 for local drives, 7.5ms for local | ||
| 879 | cdrom drive, ~5-10ms or more for remote drives on LAN). */ | ||
| 880 | volume_info_data * | ||
| 881 | GetCachedVolumeInformation (char * root_dir) | ||
| 882 | { | ||
| 883 | volume_info_data * info; | ||
| 884 | char default_root[ MAX_PATH ]; | ||
| 885 | |||
| 886 | /* NULL for root_dir means use root from current directory. */ | ||
| 887 | if (root_dir == NULL) | ||
| 888 | { | ||
| 889 | if (GetCurrentDirectory (MAX_PATH, default_root) == 0) | ||
| 890 | return NULL; | ||
| 891 | parse_root (default_root, &root_dir); | ||
| 892 | *root_dir = 0; | ||
| 893 | root_dir = default_root; | ||
| 894 | } | ||
| 895 | |||
| 896 | /* Local fixed drives can be cached permanently. Removable drives | ||
| 897 | cannot be cached permanently, since the volume name and serial | ||
| 898 | number (if nothing else) can change. Remote drives should be | ||
| 899 | treated as if they are removable, since there is no sure way to | ||
| 900 | tell whether they are or not. Also, the UNC association of drive | ||
| 901 | letters mapped to remote volumes can be changed at any time (even | ||
| 902 | by other processes) without notice. | ||
| 903 | |||
| 904 | As a compromise, so we can benefit from caching info for remote | ||
| 905 | volumes, we use a simple expiry mechanism to invalidate cache | ||
| 906 | entries that are more than ten seconds old. */ | ||
| 907 | |||
| 908 | #if 0 | ||
| 909 | /* No point doing this, because WNetGetConnection is even slower than | ||
| 910 | GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW, | ||
| 911 | GetDriveType is about the only call of this type which does not | ||
| 912 | involve network access, and so is extremely quick). */ | ||
| 913 | |||
| 914 | /* Map drive letter to UNC if remote. */ | ||
| 915 | if ( isalpha( root_dir[0] ) && !fixed[ DRIVE_INDEX( root_dir[0] ) ] ) | ||
| 916 | { | ||
| 917 | char remote_name[ 256 ]; | ||
| 918 | char drive[3] = { root_dir[0], ':' }; | ||
| 919 | |||
| 920 | if (WNetGetConnection (drive, remote_name, sizeof (remote_name)) | ||
| 921 | == NO_ERROR) | ||
| 922 | /* do something */ ; | ||
| 923 | } | ||
| 924 | #endif | ||
| 925 | |||
| 926 | info = lookup_volume_info (root_dir); | ||
| 927 | |||
| 928 | if (info == NULL || ! VOLINFO_STILL_VALID (root_dir, info)) | ||
| 929 | { | ||
| 930 | char name[ 256 ]; | ||
| 931 | DWORD serialnum; | ||
| 932 | DWORD maxcomp; | ||
| 933 | DWORD flags; | ||
| 934 | char type[ 256 ]; | ||
| 935 | |||
| 936 | /* Info is not cached, or is stale. */ | ||
| 937 | if (!GetVolumeInformation (root_dir, | ||
| 938 | name, sizeof (name), | ||
| 939 | &serialnum, | ||
| 940 | &maxcomp, | ||
| 941 | &flags, | ||
| 942 | type, sizeof (type))) | ||
| 943 | return NULL; | ||
| 944 | |||
| 945 | /* Cache the volume information for future use, overwriting existing | ||
| 946 | entry if present. */ | ||
| 947 | if (info == NULL) | ||
| 948 | { | ||
| 949 | info = (volume_info_data *) xmalloc (sizeof (volume_info_data)); | ||
| 950 | add_volume_info (root_dir, info); | ||
| 951 | } | ||
| 952 | else | ||
| 953 | { | ||
| 954 | free (info->name); | ||
| 955 | free (info->type); | ||
| 956 | } | ||
| 957 | |||
| 958 | info->name = strdup (name); | ||
| 959 | info->serialnum = serialnum; | ||
| 960 | info->maxcomp = maxcomp; | ||
| 961 | info->flags = flags; | ||
| 962 | info->type = strdup (type); | ||
| 963 | info->timestamp = GetTickCount (); | ||
| 964 | } | ||
| 965 | |||
| 966 | return info; | ||
| 967 | } | ||
| 763 | 968 | ||
| 764 | /* Get information on the volume where name is held; set path pointer to | 969 | /* Get information on the volume where name is held; set path pointer to |
| 765 | start of pathname in name (past UNC header\volume header if present). */ | 970 | start of pathname in name (past UNC header\volume header if present). */ |
| @@ -768,6 +973,7 @@ get_volume_info (const char * name, const char ** pPath) | |||
| 768 | { | 973 | { |
| 769 | char temp[MAX_PATH]; | 974 | char temp[MAX_PATH]; |
| 770 | char *rootname = NULL; /* default to current volume */ | 975 | char *rootname = NULL; /* default to current volume */ |
| 976 | volume_info_data * info; | ||
| 771 | 977 | ||
| 772 | if (name == NULL) | 978 | if (name == NULL) |
| 773 | return FALSE; | 979 | return FALSE; |
| @@ -801,13 +1007,11 @@ get_volume_info (const char * name, const char ** pPath) | |||
| 801 | if (pPath) | 1007 | if (pPath) |
| 802 | *pPath = name; | 1008 | *pPath = name; |
| 803 | 1009 | ||
| 804 | if (GetVolumeInformation (rootname, | 1010 | info = GetCachedVolumeInformation (rootname); |
| 805 | volume_info.name, 32, | 1011 | if (info != NULL) |
| 806 | &volume_info.serialnum, | ||
| 807 | &volume_info.maxcomp, | ||
| 808 | &volume_info.flags, | ||
| 809 | volume_info.type, 32)) | ||
| 810 | { | 1012 | { |
| 1013 | /* Set global referenced by other functions. */ | ||
| 1014 | volume_info = *info; | ||
| 811 | return TRUE; | 1015 | return TRUE; |
| 812 | } | 1016 | } |
| 813 | return FALSE; | 1017 | return FALSE; |
| @@ -831,6 +1035,7 @@ map_w32_filename (const char * name, const char ** pPath) | |||
| 831 | char * str = shortname; | 1035 | char * str = shortname; |
| 832 | char c; | 1036 | char c; |
| 833 | char * path; | 1037 | char * path; |
| 1038 | const char * save_name = name; | ||
| 834 | 1039 | ||
| 835 | if (is_fat_volume (name, &path)) /* truncate to 8.3 */ | 1040 | if (is_fat_volume (name, &path)) /* truncate to 8.3 */ |
| 836 | { | 1041 | { |
| @@ -915,11 +1120,107 @@ map_w32_filename (const char * name, const char ** pPath) | |||
| 915 | } | 1120 | } |
| 916 | 1121 | ||
| 917 | if (pPath) | 1122 | if (pPath) |
| 918 | *pPath = shortname + (path - name); | 1123 | *pPath = shortname + (path - save_name); |
| 919 | 1124 | ||
| 920 | return shortname; | 1125 | return shortname; |
| 921 | } | 1126 | } |
| 922 | 1127 | ||
| 1128 | /* Emulate the Unix directory procedures opendir, closedir, | ||
| 1129 | and readdir. We can't use the procedures supplied in sysdep.c, | ||
| 1130 | so we provide them here. */ | ||
| 1131 | |||
| 1132 | struct direct dir_static; /* simulated directory contents */ | ||
| 1133 | static HANDLE dir_find_handle = INVALID_HANDLE_VALUE; | ||
| 1134 | static int dir_is_fat; | ||
| 1135 | static char dir_pathname[MAXPATHLEN+1]; | ||
| 1136 | static WIN32_FIND_DATA dir_find_data; | ||
| 1137 | |||
| 1138 | DIR * | ||
| 1139 | opendir (char *filename) | ||
| 1140 | { | ||
| 1141 | DIR *dirp; | ||
| 1142 | |||
| 1143 | /* Opening is done by FindFirstFile. However, a read is inherent to | ||
| 1144 | this operation, so we defer the open until read time. */ | ||
| 1145 | |||
| 1146 | if (!(dirp = (DIR *) malloc (sizeof (DIR)))) | ||
| 1147 | return NULL; | ||
| 1148 | if (dir_find_handle != INVALID_HANDLE_VALUE) | ||
| 1149 | return NULL; | ||
| 1150 | |||
| 1151 | dirp->dd_fd = 0; | ||
| 1152 | dirp->dd_loc = 0; | ||
| 1153 | dirp->dd_size = 0; | ||
| 1154 | |||
| 1155 | strncpy (dir_pathname, map_w32_filename (filename, NULL), MAXPATHLEN); | ||
| 1156 | dir_pathname[MAXPATHLEN] = '\0'; | ||
| 1157 | dir_is_fat = is_fat_volume (filename, NULL); | ||
| 1158 | |||
| 1159 | return dirp; | ||
| 1160 | } | ||
| 1161 | |||
| 1162 | void | ||
| 1163 | closedir (DIR *dirp) | ||
| 1164 | { | ||
| 1165 | /* If we have a find-handle open, close it. */ | ||
| 1166 | if (dir_find_handle != INVALID_HANDLE_VALUE) | ||
| 1167 | { | ||
| 1168 | FindClose (dir_find_handle); | ||
| 1169 | dir_find_handle = INVALID_HANDLE_VALUE; | ||
| 1170 | } | ||
| 1171 | xfree ((char *) dirp); | ||
| 1172 | } | ||
| 1173 | |||
| 1174 | struct direct * | ||
| 1175 | readdir (DIR *dirp) | ||
| 1176 | { | ||
| 1177 | /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */ | ||
| 1178 | if (dir_find_handle == INVALID_HANDLE_VALUE) | ||
| 1179 | { | ||
| 1180 | char filename[MAXNAMLEN + 3]; | ||
| 1181 | int ln; | ||
| 1182 | |||
| 1183 | strcpy (filename, dir_pathname); | ||
| 1184 | ln = strlen (filename) - 1; | ||
| 1185 | if (!IS_DIRECTORY_SEP (filename[ln])) | ||
| 1186 | strcat (filename, "\\"); | ||
| 1187 | strcat (filename, "*"); | ||
| 1188 | |||
| 1189 | dir_find_handle = FindFirstFile (filename, &dir_find_data); | ||
| 1190 | |||
| 1191 | if (dir_find_handle == INVALID_HANDLE_VALUE) | ||
| 1192 | return NULL; | ||
| 1193 | } | ||
| 1194 | else | ||
| 1195 | { | ||
| 1196 | if (!FindNextFile (dir_find_handle, &dir_find_data)) | ||
| 1197 | return NULL; | ||
| 1198 | } | ||
| 1199 | |||
| 1200 | /* Emacs never uses this value, so don't bother making it match | ||
| 1201 | value returned by stat(). */ | ||
| 1202 | dir_static.d_ino = 1; | ||
| 1203 | |||
| 1204 | dir_static.d_reclen = sizeof (struct direct) - MAXNAMLEN + 3 + | ||
| 1205 | dir_static.d_namlen - dir_static.d_namlen % 4; | ||
| 1206 | |||
| 1207 | dir_static.d_namlen = strlen (dir_find_data.cFileName); | ||
| 1208 | strcpy (dir_static.d_name, dir_find_data.cFileName); | ||
| 1209 | if (dir_is_fat) | ||
| 1210 | _strlwr (dir_static.d_name); | ||
| 1211 | else if (!NILP (Vw32_downcase_file_names)) | ||
| 1212 | { | ||
| 1213 | register char *p; | ||
| 1214 | for (p = dir_static.d_name; *p; p++) | ||
| 1215 | if (*p >= 'a' && *p <= 'z') | ||
| 1216 | break; | ||
| 1217 | if (!*p) | ||
| 1218 | _strlwr (dir_static.d_name); | ||
| 1219 | } | ||
| 1220 | |||
| 1221 | return &dir_static; | ||
| 1222 | } | ||
| 1223 | |||
| 923 | 1224 | ||
| 924 | /* Shadow some MSVC runtime functions to map requests for long filenames | 1225 | /* Shadow some MSVC runtime functions to map requests for long filenames |
| 925 | to reasonable short names if necessary. This was originally added to | 1226 | to reasonable short names if necessary. This was originally added to |
| @@ -991,14 +1292,80 @@ sys_fopen(const char * path, const char * mode) | |||
| 991 | if (fd < 0) | 1292 | if (fd < 0) |
| 992 | return NULL; | 1293 | return NULL; |
| 993 | 1294 | ||
| 994 | return fdopen (fd, mode_save); | 1295 | return _fdopen (fd, mode_save); |
| 995 | } | 1296 | } |
| 996 | 1297 | ||
| 1298 | /* This only works on NTFS volumes, but is useful to have. */ | ||
| 997 | int | 1299 | int |
| 998 | sys_link (const char * path1, const char * path2) | 1300 | sys_link (const char * old, const char * new) |
| 999 | { | 1301 | { |
| 1000 | errno = EINVAL; | 1302 | HANDLE fileh; |
| 1001 | return -1; | 1303 | int result = -1; |
| 1304 | char oldname[MAX_PATH], newname[MAX_PATH]; | ||
| 1305 | |||
| 1306 | if (old == NULL || new == NULL) | ||
| 1307 | { | ||
| 1308 | errno = ENOENT; | ||
| 1309 | return -1; | ||
| 1310 | } | ||
| 1311 | |||
| 1312 | strcpy (oldname, map_w32_filename (old, NULL)); | ||
| 1313 | strcpy (newname, map_w32_filename (new, NULL)); | ||
| 1314 | |||
| 1315 | fileh = CreateFile (oldname, 0, 0, NULL, OPEN_EXISTING, | ||
| 1316 | FILE_FLAG_BACKUP_SEMANTICS, NULL); | ||
| 1317 | if (fileh != INVALID_HANDLE_VALUE) | ||
| 1318 | { | ||
| 1319 | int wlen; | ||
| 1320 | |||
| 1321 | /* Confusingly, the "alternate" stream name field does not apply | ||
| 1322 | when restoring a hard link, and instead contains the actual | ||
| 1323 | stream data for the link (ie. the name of the link to create). | ||
| 1324 | The WIN32_STREAM_ID structure before the cStreamName field is | ||
| 1325 | the stream header, which is then immediately followed by the | ||
| 1326 | stream data. */ | ||
| 1327 | |||
| 1328 | struct { | ||
| 1329 | WIN32_STREAM_ID wid; | ||
| 1330 | WCHAR wbuffer[MAX_PATH]; /* extra space for link name */ | ||
| 1331 | } data; | ||
| 1332 | |||
| 1333 | wlen = MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, newname, -1, | ||
| 1334 | data.wid.cStreamName, MAX_PATH); | ||
| 1335 | if (wlen > 0) | ||
| 1336 | { | ||
| 1337 | LPVOID context = NULL; | ||
| 1338 | DWORD wbytes = 0; | ||
| 1339 | |||
| 1340 | data.wid.dwStreamId = BACKUP_LINK; | ||
| 1341 | data.wid.dwStreamAttributes = 0; | ||
| 1342 | data.wid.Size.LowPart = wlen * sizeof(WCHAR); | ||
| 1343 | data.wid.Size.HighPart = 0; | ||
| 1344 | data.wid.dwStreamNameSize = 0; | ||
| 1345 | |||
| 1346 | if (BackupWrite (fileh, (LPBYTE)&data, | ||
| 1347 | offsetof (WIN32_STREAM_ID, cStreamName) | ||
| 1348 | + data.wid.Size.LowPart, | ||
| 1349 | &wbytes, FALSE, FALSE, &context) | ||
| 1350 | && BackupWrite (fileh, NULL, 0, &wbytes, TRUE, FALSE, &context)) | ||
| 1351 | { | ||
| 1352 | /* succeeded */ | ||
| 1353 | result = 0; | ||
| 1354 | } | ||
| 1355 | else | ||
| 1356 | { | ||
| 1357 | /* Should try mapping GetLastError to errno; for now just | ||
| 1358 | indicate a general error (eg. links not supported). */ | ||
| 1359 | errno = EINVAL; // perhaps EMLINK? | ||
| 1360 | } | ||
| 1361 | } | ||
| 1362 | |||
| 1363 | CloseHandle (fileh); | ||
| 1364 | } | ||
| 1365 | else | ||
| 1366 | errno = ENOENT; | ||
| 1367 | |||
| 1368 | return result; | ||
| 1002 | } | 1369 | } |
| 1003 | 1370 | ||
| 1004 | int | 1371 | int |
| @@ -1085,7 +1452,7 @@ sys_rename (const char * oldname, const char * newname) | |||
| 1085 | 1452 | ||
| 1086 | strcpy (temp, map_w32_filename (oldname, NULL)); | 1453 | strcpy (temp, map_w32_filename (oldname, NULL)); |
| 1087 | 1454 | ||
| 1088 | if (GetVersion () & 0x80000000) | 1455 | if (os_subtype == OS_WIN95) |
| 1089 | { | 1456 | { |
| 1090 | char * p; | 1457 | char * p; |
| 1091 | 1458 | ||
| @@ -1093,11 +1460,10 @@ sys_rename (const char * oldname, const char * newname) | |||
| 1093 | p++; | 1460 | p++; |
| 1094 | else | 1461 | else |
| 1095 | p = temp; | 1462 | p = temp; |
| 1096 | strcpy (p, "__XXXXXX"); | ||
| 1097 | sys_mktemp (temp); | ||
| 1098 | /* Force temp name to require a manufactured 8.3 alias - this | 1463 | /* Force temp name to require a manufactured 8.3 alias - this |
| 1099 | seems to make the second rename work properly. */ | 1464 | seems to make the second rename work properly. */ |
| 1100 | strcat (temp, ".long"); | 1465 | strcpy (p, "_rename_temp.XXXXXX"); |
| 1466 | sys_mktemp (temp); | ||
| 1101 | if (rename (map_w32_filename (oldname, NULL), temp) < 0) | 1467 | if (rename (map_w32_filename (oldname, NULL), temp) < 0) |
| 1102 | return -1; | 1468 | return -1; |
| 1103 | } | 1469 | } |
| @@ -1107,6 +1473,9 @@ sys_rename (const char * oldname, const char * newname) | |||
| 1107 | However, don't do this if we are just changing the case of the file | 1473 | However, don't do this if we are just changing the case of the file |
| 1108 | name - we will end up deleting the file we are trying to rename! */ | 1474 | name - we will end up deleting the file we are trying to rename! */ |
| 1109 | newname = map_w32_filename (newname, NULL); | 1475 | newname = map_w32_filename (newname, NULL); |
| 1476 | |||
| 1477 | /* TODO: Use GetInformationByHandle (on NT) to ensure newname and temp | ||
| 1478 | do not refer to the same file, eg. through share aliases. */ | ||
| 1110 | if (stricmp (newname, temp) != 0 | 1479 | if (stricmp (newname, temp) != 0 |
| 1111 | && (attr = GetFileAttributes (newname)) != -1 | 1480 | && (attr = GetFileAttributes (newname)) != -1 |
| 1112 | && (attr & FILE_ATTRIBUTE_DIRECTORY) == 0) | 1481 | && (attr & FILE_ATTRIBUTE_DIRECTORY) == 0) |
| @@ -1199,38 +1568,49 @@ convert_from_time_t (time_t time, FILETIME * pft) | |||
| 1199 | } | 1568 | } |
| 1200 | #endif | 1569 | #endif |
| 1201 | 1570 | ||
| 1202 | /* "PJW" algorithm (see the "Dragon" compiler book). */ | 1571 | #if 0 |
| 1572 | /* No reason to keep this; faking inode values either by hashing or even | ||
| 1573 | using the file index from GetInformationByHandle, is not perfect and | ||
| 1574 | so by default Emacs doesn't use the inode values on Windows. | ||
| 1575 | Instead, we now determine file-truename correctly (except for | ||
| 1576 | possible drive aliasing etc). */ | ||
| 1577 | |||
| 1578 | /* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */ | ||
| 1203 | static unsigned | 1579 | static unsigned |
| 1204 | hashval (const char * str) | 1580 | hashval (const unsigned char * str) |
| 1205 | { | 1581 | { |
| 1206 | unsigned h = 0; | 1582 | unsigned h = 0; |
| 1207 | unsigned g; | ||
| 1208 | while (*str) | 1583 | while (*str) |
| 1209 | { | 1584 | { |
| 1210 | h = (h << 4) + *str++; | 1585 | h = (h << 4) + *str++; |
| 1211 | if ((g = h & 0xf0000000) != 0) | 1586 | h ^= (h >> 28); |
| 1212 | h = (h ^ (g >> 24)) & 0x0fffffff; | ||
| 1213 | } | 1587 | } |
| 1214 | return h; | 1588 | return h; |
| 1215 | } | 1589 | } |
| 1216 | 1590 | ||
| 1217 | /* Return the hash value of the canonical pathname, excluding the | 1591 | /* Return the hash value of the canonical pathname, excluding the |
| 1218 | drive/UNC header, to get a hopefully unique inode number. */ | 1592 | drive/UNC header, to get a hopefully unique inode number. */ |
| 1219 | static _ino_t | 1593 | static DWORD |
| 1220 | generate_inode_val (const char * name) | 1594 | generate_inode_val (const char * name) |
| 1221 | { | 1595 | { |
| 1222 | char fullname[ MAX_PATH ]; | 1596 | char fullname[ MAX_PATH ]; |
| 1223 | char * p; | 1597 | char * p; |
| 1224 | unsigned hash; | 1598 | unsigned hash; |
| 1225 | 1599 | ||
| 1226 | GetFullPathName (name, sizeof (fullname), fullname, &p); | 1600 | /* Get the truly canonical filename, if it exists. (Note: this |
| 1227 | get_volume_info (fullname, &p); | 1601 | doesn't resolve aliasing due to subst commands, or recognise hard |
| 1602 | links. */ | ||
| 1603 | if (!w32_get_long_filename ((char *)name, fullname, MAX_PATH)) | ||
| 1604 | abort (); | ||
| 1605 | |||
| 1606 | parse_root (fullname, &p); | ||
| 1228 | /* Normal W32 filesystems are still case insensitive. */ | 1607 | /* Normal W32 filesystems are still case insensitive. */ |
| 1229 | _strlwr (p); | 1608 | _strlwr (p); |
| 1230 | hash = hashval (p); | 1609 | return hashval (p); |
| 1231 | return (_ino_t) (hash ^ (hash >> 16)); | ||
| 1232 | } | 1610 | } |
| 1233 | 1611 | ||
| 1612 | #endif | ||
| 1613 | |||
| 1234 | /* MSVC stat function can't cope with UNC names and has other bugs, so | 1614 | /* MSVC stat function can't cope with UNC names and has other bugs, so |
| 1235 | replace it with our own. This also allows us to calculate consistent | 1615 | replace it with our own. This also allows us to calculate consistent |
| 1236 | inode values without hacks in the main Emacs code. */ | 1616 | inode values without hacks in the main Emacs code. */ |
| @@ -1240,6 +1620,7 @@ stat (const char * path, struct stat * buf) | |||
| 1240 | char * name; | 1620 | char * name; |
| 1241 | WIN32_FIND_DATA wfd; | 1621 | WIN32_FIND_DATA wfd; |
| 1242 | HANDLE fh; | 1622 | HANDLE fh; |
| 1623 | DWORD fake_inode; | ||
| 1243 | int permission; | 1624 | int permission; |
| 1244 | int len; | 1625 | int len; |
| 1245 | int rootdir = FALSE; | 1626 | int rootdir = FALSE; |
| @@ -1286,30 +1667,46 @@ stat (const char * path, struct stat * buf) | |||
| 1286 | { | 1667 | { |
| 1287 | if (IS_DIRECTORY_SEP (name[len-1])) | 1668 | if (IS_DIRECTORY_SEP (name[len-1])) |
| 1288 | name[len - 1] = 0; | 1669 | name[len - 1] = 0; |
| 1289 | fh = FindFirstFile (name, &wfd); | 1670 | |
| 1290 | if (fh == INVALID_HANDLE_VALUE) | 1671 | /* (This is hacky, but helps when doing file completions on |
| 1672 | network drives.) Optimize by using information available from | ||
| 1673 | active readdir if possible. */ | ||
| 1674 | if (dir_find_handle != INVALID_HANDLE_VALUE | ||
| 1675 | && (len = strlen (dir_pathname)), | ||
| 1676 | strnicmp (name, dir_pathname, len) == 0 | ||
| 1677 | && IS_DIRECTORY_SEP (name[len]) | ||
| 1678 | && stricmp (name + len + 1, dir_static.d_name) == 0) | ||
| 1291 | { | 1679 | { |
| 1292 | errno = ENOENT; | 1680 | /* This was the last entry returned by readdir. */ |
| 1293 | return -1; | 1681 | wfd = dir_find_data; |
| 1682 | } | ||
| 1683 | else | ||
| 1684 | { | ||
| 1685 | fh = FindFirstFile (name, &wfd); | ||
| 1686 | if (fh == INVALID_HANDLE_VALUE) | ||
| 1687 | { | ||
| 1688 | errno = ENOENT; | ||
| 1689 | return -1; | ||
| 1690 | } | ||
| 1691 | FindClose (fh); | ||
| 1294 | } | 1692 | } |
| 1295 | FindClose (fh); | ||
| 1296 | } | 1693 | } |
| 1297 | 1694 | ||
| 1298 | if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) | 1695 | if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) |
| 1299 | { | 1696 | { |
| 1300 | buf->st_mode = _S_IFDIR; | 1697 | buf->st_mode = _S_IFDIR; |
| 1301 | buf->st_nlink = 2; /* doesn't really matter */ | 1698 | buf->st_nlink = 2; /* doesn't really matter */ |
| 1699 | fake_inode = 0; /* this doesn't either I think */ | ||
| 1302 | } | 1700 | } |
| 1303 | else | 1701 | else if (!NILP (Vw32_get_true_file_attributes)) |
| 1304 | { | 1702 | { |
| 1305 | #if 0 | ||
| 1306 | /* This is more accurate in terms of gettting the correct number | 1703 | /* This is more accurate in terms of gettting the correct number |
| 1307 | of links, but is quite slow (it is noticable when Emacs is | 1704 | of links, but is quite slow (it is noticable when Emacs is |
| 1308 | making a list of file name completions). */ | 1705 | making a list of file name completions). */ |
| 1309 | BY_HANDLE_FILE_INFORMATION info; | 1706 | BY_HANDLE_FILE_INFORMATION info; |
| 1310 | 1707 | ||
| 1311 | fh = CreateFile (name, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, | 1708 | /* No access rights required to get info. */ |
| 1312 | NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); | 1709 | fh = CreateFile (name, 0, 0, NULL, OPEN_EXISTING, 0, NULL); |
| 1313 | 1710 | ||
| 1314 | if (GetFileInformationByHandle (fh, &info)) | 1711 | if (GetFileInformationByHandle (fh, &info)) |
| 1315 | { | 1712 | { |
| @@ -1327,9 +1724,12 @@ stat (const char * path, struct stat * buf) | |||
| 1327 | buf->st_mode = _S_IFCHR; | 1724 | buf->st_mode = _S_IFCHR; |
| 1328 | } | 1725 | } |
| 1329 | buf->st_nlink = info.nNumberOfLinks; | 1726 | buf->st_nlink = info.nNumberOfLinks; |
| 1330 | /* Could use file index, but this is not guaranteed to be | 1727 | /* Might as well use file index to fake inode values, but this |
| 1331 | unique unless we keep a handle open all the time. */ | 1728 | is not guaranteed to be unique unless we keep a handle open |
| 1332 | /* buf->st_ino = info.nFileIndexLow ^ info.nFileIndexHigh; */ | 1729 | all the time (even then there are situations where it is |
| 1730 | not unique). Reputedly, there are at most 48 bits of info | ||
| 1731 | (on NTFS, presumably less on FAT). */ | ||
| 1732 | fake_inode = info.nFileIndexLow ^ info.nFileIndexHigh; | ||
| 1333 | CloseHandle (fh); | 1733 | CloseHandle (fh); |
| 1334 | } | 1734 | } |
| 1335 | else | 1735 | else |
| @@ -1337,11 +1737,32 @@ stat (const char * path, struct stat * buf) | |||
| 1337 | errno = EACCES; | 1737 | errno = EACCES; |
| 1338 | return -1; | 1738 | return -1; |
| 1339 | } | 1739 | } |
| 1340 | #else | 1740 | } |
| 1741 | else | ||
| 1742 | { | ||
| 1743 | /* Don't bother to make this information more accurate. */ | ||
| 1341 | buf->st_mode = _S_IFREG; | 1744 | buf->st_mode = _S_IFREG; |
| 1342 | buf->st_nlink = 1; | 1745 | buf->st_nlink = 1; |
| 1343 | #endif | 1746 | fake_inode = 0; |
| 1747 | } | ||
| 1748 | |||
| 1749 | #if 0 | ||
| 1750 | /* Not sure if there is any point in this. */ | ||
| 1751 | if (!NILP (Vw32_generate_fake_inodes)) | ||
| 1752 | fake_inode = generate_inode_val (name); | ||
| 1753 | else if (fake_inode == 0) | ||
| 1754 | { | ||
| 1755 | /* For want of something better, try to make everything unique. */ | ||
| 1756 | static DWORD gen_num = 0; | ||
| 1757 | fake_inode = ++gen_num; | ||
| 1344 | } | 1758 | } |
| 1759 | #endif | ||
| 1760 | |||
| 1761 | /* MSVC defines _ino_t to be short; other libc's might not. */ | ||
| 1762 | if (sizeof (buf->st_ino) == 2) | ||
| 1763 | buf->st_ino = fake_inode ^ (fake_inode >> 16); | ||
| 1764 | else | ||
| 1765 | buf->st_ino = fake_inode; | ||
| 1345 | 1766 | ||
| 1346 | /* consider files to belong to current user */ | 1767 | /* consider files to belong to current user */ |
| 1347 | buf->st_uid = the_passwd.pw_uid; | 1768 | buf->st_uid = the_passwd.pw_uid; |
| @@ -1351,7 +1772,6 @@ stat (const char * path, struct stat * buf) | |||
| 1351 | buf->st_dev = volume_info.serialnum; | 1772 | buf->st_dev = volume_info.serialnum; |
| 1352 | buf->st_rdev = volume_info.serialnum; | 1773 | buf->st_rdev = volume_info.serialnum; |
| 1353 | 1774 | ||
| 1354 | buf->st_ino = generate_inode_val (name); | ||
| 1355 | 1775 | ||
| 1356 | buf->st_size = wfd.nFileSizeLow; | 1776 | buf->st_size = wfd.nFileSizeLow; |
| 1357 | 1777 | ||
| @@ -1373,11 +1793,11 @@ stat (const char * path, struct stat * buf) | |||
| 1373 | else | 1793 | else |
| 1374 | { | 1794 | { |
| 1375 | char * p = strrchr (name, '.'); | 1795 | char * p = strrchr (name, '.'); |
| 1376 | if (p != NULL && | 1796 | if (p != NULL |
| 1377 | (stricmp (p, ".exe") == 0 || | 1797 | && (stricmp (p, ".exe") == 0 || |
| 1378 | stricmp (p, ".com") == 0 || | 1798 | stricmp (p, ".com") == 0 || |
| 1379 | stricmp (p, ".bat") == 0 || | 1799 | stricmp (p, ".bat") == 0 || |
| 1380 | stricmp (p, ".cmd") == 0)) | 1800 | stricmp (p, ".cmd") == 0)) |
| 1381 | permission |= _S_IEXEC; | 1801 | permission |= _S_IEXEC; |
| 1382 | } | 1802 | } |
| 1383 | 1803 | ||
| @@ -1919,42 +2339,22 @@ sys_pipe (int * phandles) | |||
| 1919 | unsigned flags; | 2339 | unsigned flags; |
| 1920 | child_process * cp; | 2340 | child_process * cp; |
| 1921 | 2341 | ||
| 1922 | /* make pipe handles non-inheritable; when we spawn a child, | 2342 | /* make pipe handles non-inheritable; when we spawn a child, we |
| 1923 | we replace the relevant handle with an inheritable one. */ | 2343 | replace the relevant handle with an inheritable one. Also put |
| 1924 | rc = _pipe (phandles, 0, _O_NOINHERIT); | 2344 | pipes into binary mode; we will do text mode translation ourselves |
| 2345 | if required. */ | ||
| 2346 | rc = _pipe (phandles, 0, _O_NOINHERIT | _O_BINARY); | ||
| 1925 | 2347 | ||
| 1926 | if (rc == 0) | 2348 | if (rc == 0) |
| 1927 | { | 2349 | { |
| 1928 | /* set internal flags, and put read and write handles into binary | ||
| 1929 | mode as necessary; if not in binary mode, set the MSVC internal | ||
| 1930 | FDEV (0x40) flag to prevent _read from treating ^Z as eof (this | ||
| 1931 | could otherwise allow Emacs to hang because it then waits | ||
| 1932 | indefinitely for the child process to exit, when it might not be | ||
| 1933 | finished). */ | ||
| 1934 | flags = FILE_PIPE | FILE_READ; | 2350 | flags = FILE_PIPE | FILE_READ; |
| 1935 | if (!NILP (Vbinary_process_output)) | 2351 | if (!NILP (Vbinary_process_output)) |
| 1936 | { | 2352 | flags |= FILE_BINARY; |
| 1937 | flags |= FILE_BINARY; | ||
| 1938 | setmode (phandles[0], _O_BINARY); | ||
| 1939 | } | ||
| 1940 | #if (_MSC_VER == 900) | ||
| 1941 | else | ||
| 1942 | _osfile[phandles[0]] |= 0x40; | ||
| 1943 | #endif | ||
| 1944 | |||
| 1945 | fd_info[phandles[0]].flags = flags; | 2353 | fd_info[phandles[0]].flags = flags; |
| 1946 | 2354 | ||
| 1947 | flags = FILE_PIPE | FILE_WRITE; | 2355 | flags = FILE_PIPE | FILE_WRITE; |
| 1948 | if (!NILP (Vbinary_process_input)) | 2356 | if (!NILP (Vbinary_process_input)) |
| 1949 | { | 2357 | flags |= FILE_BINARY; |
| 1950 | flags |= FILE_BINARY; | ||
| 1951 | setmode (phandles[1], _O_BINARY); | ||
| 1952 | } | ||
| 1953 | #if (_MSC_VER == 900) | ||
| 1954 | else | ||
| 1955 | _osfile[phandles[1]] |= 0x40; | ||
| 1956 | #endif | ||
| 1957 | |||
| 1958 | fd_info[phandles[1]].flags = flags; | 2358 | fd_info[phandles[1]].flags = flags; |
| 1959 | } | 2359 | } |
| 1960 | 2360 | ||
| @@ -1991,7 +2391,6 @@ _sys_read_ahead (int fd) | |||
| 1991 | 2391 | ||
| 1992 | if (fd_info[fd].flags & FILE_PIPE) | 2392 | if (fd_info[fd].flags & FILE_PIPE) |
| 1993 | { | 2393 | { |
| 1994 | /* Use read to get CRLF translation */ | ||
| 1995 | rc = _read (fd, &cp->chr, sizeof (char)); | 2394 | rc = _read (fd, &cp->chr, sizeof (char)); |
| 1996 | 2395 | ||
| 1997 | /* Give subprocess time to buffer some more output for us before | 2396 | /* Give subprocess time to buffer some more output for us before |
| @@ -2031,9 +2430,9 @@ int | |||
| 2031 | sys_read (int fd, char * buffer, unsigned int count) | 2430 | sys_read (int fd, char * buffer, unsigned int count) |
| 2032 | { | 2431 | { |
| 2033 | int nchars; | 2432 | int nchars; |
| 2034 | int extra = 0; | ||
| 2035 | int to_read; | 2433 | int to_read; |
| 2036 | DWORD waiting; | 2434 | DWORD waiting; |
| 2435 | char * orig_buffer = buffer; | ||
| 2037 | 2436 | ||
| 2038 | if (fd < 0 || fd >= MAXDESC) | 2437 | if (fd < 0 || fd >= MAXDESC) |
| 2039 | { | 2438 | { |
| @@ -2051,6 +2450,17 @@ sys_read (int fd, char * buffer, unsigned int count) | |||
| 2051 | return -1; | 2450 | return -1; |
| 2052 | } | 2451 | } |
| 2053 | 2452 | ||
| 2453 | nchars = 0; | ||
| 2454 | |||
| 2455 | /* re-read CR carried over from last read */ | ||
| 2456 | if (fd_info[fd].flags & FILE_LAST_CR) | ||
| 2457 | { | ||
| 2458 | if (fd_info[fd].flags & FILE_BINARY) abort (); | ||
| 2459 | *buffer++ = 0x0d; | ||
| 2460 | count--; | ||
| 2461 | nchars++; | ||
| 2462 | } | ||
| 2463 | |||
| 2054 | /* presence of a child_process structure means we are operating in | 2464 | /* presence of a child_process structure means we are operating in |
| 2055 | non-blocking mode - otherwise we just call _read directly. | 2465 | non-blocking mode - otherwise we just call _read directly. |
| 2056 | Note that the child_process structure might be missing because | 2466 | Note that the child_process structure might be missing because |
| @@ -2077,7 +2487,7 @@ sys_read (int fd, char * buffer, unsigned int count) | |||
| 2077 | /* consume read-ahead char */ | 2487 | /* consume read-ahead char */ |
| 2078 | *buffer++ = cp->chr; | 2488 | *buffer++ = cp->chr; |
| 2079 | count--; | 2489 | count--; |
| 2080 | extra = 1; | 2490 | nchars++; |
| 2081 | cp->status = STATUS_READ_ACKNOWLEDGED; | 2491 | cp->status = STATUS_READ_ACKNOWLEDGED; |
| 2082 | ResetEvent (cp->char_avail); | 2492 | ResetEvent (cp->char_avail); |
| 2083 | 2493 | ||
| @@ -2095,8 +2505,7 @@ sys_read (int fd, char * buffer, unsigned int count) | |||
| 2095 | PeekNamedPipe ((HANDLE) _get_osfhandle (fd), NULL, 0, NULL, &waiting, NULL); | 2505 | PeekNamedPipe ((HANDLE) _get_osfhandle (fd), NULL, 0, NULL, &waiting, NULL); |
| 2096 | to_read = min (waiting, (DWORD) count); | 2506 | to_read = min (waiting, (DWORD) count); |
| 2097 | 2507 | ||
| 2098 | /* Use read to get CRLF translation */ | 2508 | nchars += _read (fd, buffer, to_read); |
| 2099 | nchars = _read (fd, buffer, to_read); | ||
| 2100 | } | 2509 | } |
| 2101 | #ifdef HAVE_SOCKETS | 2510 | #ifdef HAVE_SOCKETS |
| 2102 | else /* FILE_SOCKET */ | 2511 | else /* FILE_SOCKET */ |
| @@ -2105,39 +2514,52 @@ sys_read (int fd, char * buffer, unsigned int count) | |||
| 2105 | 2514 | ||
| 2106 | /* do the equivalent of a non-blocking read */ | 2515 | /* do the equivalent of a non-blocking read */ |
| 2107 | pfn_ioctlsocket (SOCK_HANDLE (fd), FIONREAD, &waiting); | 2516 | pfn_ioctlsocket (SOCK_HANDLE (fd), FIONREAD, &waiting); |
| 2108 | if (waiting == 0 && extra == 0) | 2517 | if (waiting == 0 && nchars == 0) |
| 2109 | { | 2518 | { |
| 2110 | h_errno = errno = EWOULDBLOCK; | 2519 | h_errno = errno = EWOULDBLOCK; |
| 2111 | return -1; | 2520 | return -1; |
| 2112 | } | 2521 | } |
| 2113 | 2522 | ||
| 2114 | nchars = 0; | ||
| 2115 | if (waiting) | 2523 | if (waiting) |
| 2116 | { | 2524 | { |
| 2117 | /* always use binary mode for sockets */ | 2525 | /* always use binary mode for sockets */ |
| 2118 | nchars = pfn_recv (SOCK_HANDLE (fd), buffer, count, 0); | 2526 | int res = pfn_recv (SOCK_HANDLE (fd), buffer, count, 0); |
| 2119 | if (nchars == SOCKET_ERROR) | 2527 | if (res == SOCKET_ERROR) |
| 2120 | { | 2528 | { |
| 2121 | DebPrint(("sys_read.recv failed with error %d on socket %ld\n", | 2529 | DebPrint(("sys_read.recv failed with error %d on socket %ld\n", |
| 2122 | pfn_WSAGetLastError (), SOCK_HANDLE (fd))); | 2530 | pfn_WSAGetLastError (), SOCK_HANDLE (fd))); |
| 2123 | if (extra == 0) | 2531 | set_errno (); |
| 2124 | { | 2532 | return -1; |
| 2125 | set_errno (); | ||
| 2126 | return -1; | ||
| 2127 | } | ||
| 2128 | nchars = 0; | ||
| 2129 | } | 2533 | } |
| 2534 | nchars += res; | ||
| 2130 | } | 2535 | } |
| 2131 | } | 2536 | } |
| 2132 | #endif | 2537 | #endif |
| 2133 | } | 2538 | } |
| 2134 | else | 2539 | else |
| 2135 | nchars = _read (fd, buffer, count); | 2540 | nchars += _read (fd, buffer, count); |
| 2541 | |||
| 2542 | /* Perform text mode translation if required. */ | ||
| 2543 | if ((fd_info[fd].flags & FILE_BINARY) == 0) | ||
| 2544 | { | ||
| 2545 | nchars = crlf_to_lf (nchars, orig_buffer); | ||
| 2546 | /* If buffer contains only CR, return that. To be absolutely | ||
| 2547 | sure we should attempt to read the next char, but in | ||
| 2548 | practice a CR to be followed by LF would not appear by | ||
| 2549 | itself in the buffer. */ | ||
| 2550 | if (nchars > 1 && orig_buffer[nchars - 1] == 0x0d) | ||
| 2551 | { | ||
| 2552 | fd_info[fd].flags |= FILE_LAST_CR; | ||
| 2553 | nchars--; | ||
| 2554 | } | ||
| 2555 | else | ||
| 2556 | fd_info[fd].flags &= ~FILE_LAST_CR; | ||
| 2557 | } | ||
| 2136 | } | 2558 | } |
| 2137 | else | 2559 | else |
| 2138 | nchars = _read (fd, buffer, count); | 2560 | nchars = _read (fd, buffer, count); |
| 2139 | 2561 | ||
| 2140 | return nchars + extra; | 2562 | return nchars; |
| 2141 | } | 2563 | } |
| 2142 | 2564 | ||
| 2143 | /* For now, don't bother with a non-blocking mode */ | 2565 | /* For now, don't bother with a non-blocking mode */ |
| @@ -2153,11 +2575,46 @@ sys_write (int fd, const void * buffer, unsigned int count) | |||
| 2153 | } | 2575 | } |
| 2154 | 2576 | ||
| 2155 | if (fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET)) | 2577 | if (fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET)) |
| 2156 | if ((fd_info[fd].flags & FILE_WRITE) == 0) | 2578 | { |
| 2157 | { | 2579 | if ((fd_info[fd].flags & FILE_WRITE) == 0) |
| 2158 | errno = EBADF; | 2580 | { |
| 2159 | return -1; | 2581 | errno = EBADF; |
| 2160 | } | 2582 | return -1; |
| 2583 | } | ||
| 2584 | |||
| 2585 | /* Perform text mode translation if required. */ | ||
| 2586 | if ((fd_info[fd].flags & FILE_BINARY) == 0) | ||
| 2587 | { | ||
| 2588 | char * tmpbuf = alloca (count * 2); | ||
| 2589 | unsigned char * src = (void *)buffer; | ||
| 2590 | unsigned char * dst = tmpbuf; | ||
| 2591 | int nbytes = count; | ||
| 2592 | |||
| 2593 | while (1) | ||
| 2594 | { | ||
| 2595 | unsigned char *next; | ||
| 2596 | /* copy next line or remaining bytes */ | ||
| 2597 | next = _memccpy (dst, src, '\n', nbytes); | ||
| 2598 | if (next) | ||
| 2599 | { | ||
| 2600 | /* copied one line ending with '\n' */ | ||
| 2601 | int copied = next - dst; | ||
| 2602 | nbytes -= copied; | ||
| 2603 | src += copied; | ||
| 2604 | /* insert '\r' before '\n' */ | ||
| 2605 | next[-1] = '\r'; | ||
| 2606 | next[0] = '\n'; | ||
| 2607 | dst = next + 1; | ||
| 2608 | count++; | ||
| 2609 | } | ||
| 2610 | else | ||
| 2611 | /* copied remaining partial line -> now finished */ | ||
| 2612 | break; | ||
| 2613 | } | ||
| 2614 | buffer = tmpbuf; | ||
| 2615 | } | ||
| 2616 | } | ||
| 2617 | |||
| 2161 | #ifdef HAVE_SOCKETS | 2618 | #ifdef HAVE_SOCKETS |
| 2162 | if (fd_info[fd].flags & FILE_SOCKET) | 2619 | if (fd_info[fd].flags & FILE_SOCKET) |
| 2163 | { | 2620 | { |
| @@ -2187,8 +2644,6 @@ term_ntproc () | |||
| 2187 | #endif | 2644 | #endif |
| 2188 | } | 2645 | } |
| 2189 | 2646 | ||
| 2190 | extern BOOL dos_process_running; | ||
| 2191 | |||
| 2192 | void | 2647 | void |
| 2193 | init_ntproc () | 2648 | init_ntproc () |
| 2194 | { | 2649 | { |
| @@ -2251,39 +2706,41 @@ init_ntproc () | |||
| 2251 | if (stdin_save != INVALID_HANDLE_VALUE) | 2706 | if (stdin_save != INVALID_HANDLE_VALUE) |
| 2252 | _open_osfhandle ((long) stdin_save, O_TEXT); | 2707 | _open_osfhandle ((long) stdin_save, O_TEXT); |
| 2253 | else | 2708 | else |
| 2254 | open ("nul", O_TEXT | O_NOINHERIT | O_RDONLY); | 2709 | _open ("nul", O_TEXT | O_NOINHERIT | O_RDONLY); |
| 2255 | fdopen (0, "r"); | 2710 | _fdopen (0, "r"); |
| 2256 | 2711 | ||
| 2257 | if (stdout_save != INVALID_HANDLE_VALUE) | 2712 | if (stdout_save != INVALID_HANDLE_VALUE) |
| 2258 | _open_osfhandle ((long) stdout_save, O_TEXT); | 2713 | _open_osfhandle ((long) stdout_save, O_TEXT); |
| 2259 | else | 2714 | else |
| 2260 | open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY); | 2715 | _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY); |
| 2261 | fdopen (1, "w"); | 2716 | _fdopen (1, "w"); |
| 2262 | 2717 | ||
| 2263 | if (stderr_save != INVALID_HANDLE_VALUE) | 2718 | if (stderr_save != INVALID_HANDLE_VALUE) |
| 2264 | _open_osfhandle ((long) stderr_save, O_TEXT); | 2719 | _open_osfhandle ((long) stderr_save, O_TEXT); |
| 2265 | else | 2720 | else |
| 2266 | open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY); | 2721 | _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY); |
| 2267 | fdopen (2, "w"); | 2722 | _fdopen (2, "w"); |
| 2268 | } | 2723 | } |
| 2269 | 2724 | ||
| 2270 | /* Restrict Emacs to running only one DOS program at a time (with any | ||
| 2271 | number of W32 programs). This is to prevent the user from | ||
| 2272 | running into problems with DOS programs being run in the same VDM | ||
| 2273 | under both Windows 95 and Windows NT. | ||
| 2274 | |||
| 2275 | Note that it is possible for Emacs to run DOS programs in separate | ||
| 2276 | VDMs, but unfortunately the pipe implementation on Windows 95 then | ||
| 2277 | fails to report when the DOS process exits (which is supposed to | ||
| 2278 | break the pipe). Until this bug is fixed, or we can devise a | ||
| 2279 | work-around, we must try to avoid letting the user start more than | ||
| 2280 | one DOS program if possible. */ | ||
| 2281 | |||
| 2282 | dos_process_running = FALSE; | ||
| 2283 | |||
| 2284 | /* unfortunately, atexit depends on implementation of malloc */ | 2725 | /* unfortunately, atexit depends on implementation of malloc */ |
| 2285 | /* atexit (term_ntproc); */ | 2726 | /* atexit (term_ntproc); */ |
| 2286 | signal (SIGABRT, term_ntproc); | 2727 | signal (SIGABRT, term_ntproc); |
| 2728 | |||
| 2729 | /* determine which drives are fixed, for GetCachedVolumeInformation */ | ||
| 2730 | { | ||
| 2731 | /* GetDriveType must have trailing backslash. */ | ||
| 2732 | char drive[] = "A:\\"; | ||
| 2733 | |||
| 2734 | /* Loop over all possible drive letters */ | ||
| 2735 | while (*drive <= 'Z') | ||
| 2736 | { | ||
| 2737 | /* Record if this drive letter refers to a fixed drive. */ | ||
| 2738 | fixed_drives[DRIVE_INDEX (*drive)] = | ||
| 2739 | (GetDriveType (drive) == DRIVE_FIXED); | ||
| 2740 | |||
| 2741 | (*drive)++; | ||
| 2742 | } | ||
| 2743 | } | ||
| 2287 | } | 2744 | } |
| 2288 | 2745 | ||
| 2289 | /* end of nt.c */ | 2746 | /* end of nt.c */ |