X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/e8757f091a502b858912a4c267210e009227d6e6..a16e75cd3cb27ea5647774bc71625899f35b2fa6:/src/w32.c diff --git a/src/w32.c b/src/w32.c index 6b52fb8398..b6bb653369 100644 --- a/src/w32.c +++ b/src/w32.c @@ -31,13 +31,13 @@ along with GNU Emacs. If not, see . */ #include #include #include -#include /* for _mbspbrk */ #include #include /* must include CRT headers *before* config.h */ #include +#include /* for _mbspbrk */ #undef access #undef chdir @@ -119,9 +119,10 @@ typedef struct _PROCESS_MEMORY_COUNTERS_EX { #include #ifdef _MSC_VER -/* MSVC doesn't provide the definition of REPARSE_DATA_BUFFER, except - on ntifs.h, which cannot be included because it triggers conflicts - with other Windows API headers. So we define it here by hand. */ +/* MSVC doesn't provide the definition of REPARSE_DATA_BUFFER and the + associated macros, except on ntifs.h, which cannot be included + because it triggers conflicts with other Windows API headers. So + we define it here by hand. */ typedef struct _REPARSE_DATA_BUFFER { ULONG ReparseTag; @@ -149,6 +150,20 @@ typedef struct _REPARSE_DATA_BUFFER { } DUMMYUNIONNAME; } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; +#ifndef FILE_DEVICE_FILE_SYSTEM +#define FILE_DEVICE_FILE_SYSTEM 9 +#endif +#ifndef METHOD_BUFFERED +#define METHOD_BUFFERED 0 +#endif +#ifndef FILE_ANY_ACCESS +#define FILE_ANY_ACCESS 0x00000000 +#endif +#ifndef CTL_CODE +#define CTL_CODE(t,f,m,a) (((t)<<16)|((a)<<14)|((f)<<2)|(m)) +#endif +#define FSCTL_GET_REPARSE_POINT \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS) #endif /* TCP connection support. */ @@ -172,8 +187,10 @@ typedef struct _REPARSE_DATA_BUFFER { #undef sendto #include "w32.h" -#include "ndir.h" +#include +#include "w32common.h" #include "w32heap.h" +#include "w32select.h" #include "systime.h" #include "dispextern.h" /* for xstrcasecmp */ #include "coding.h" /* for Vlocale_coding_system */ @@ -197,6 +214,12 @@ static int enable_privilege (LPCTSTR, BOOL, TOKEN_PRIVILEGES *); static int restore_privilege (TOKEN_PRIVILEGES *); static BOOL WINAPI revert_to_self (void); +extern int sys_access (const char *, int); +extern void *e_malloc (size_t); +extern int sys_select (int, SELECT_TYPE *, SELECT_TYPE *, SELECT_TYPE *, + EMACS_TIME *, void *); + + /* Initialization states. @@ -866,23 +889,6 @@ create_symbolic_link (LPTSTR lpSymlinkFilename, return retval; } -/* Equivalent of strerror for W32 error codes. */ -char * -w32_strerror (int error_no) -{ - static char buf[500]; - - if (error_no == 0) - error_no = GetLastError (); - - buf[0] = '\0'; - if (!FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, - error_no, - 0, /* choose most suitable language */ - buf, sizeof (buf), NULL)) - sprintf (buf, "w32 error %u", error_no); - return buf; -} /* Return 1 if P is a valid pointer to an object of size SIZE. Return 0 if P is NOT a valid pointer. Return -1 if we cannot validate P. @@ -910,8 +916,18 @@ static char startup_dir[MAXPATHLEN]; /* Get the current working directory. */ char * -getwd (char *dir) +getcwd (char *dir, int dirsize) { + if (!dirsize) + { + errno = EINVAL; + return NULL; + } + if (dirsize <= strlen (startup_dir)) + { + errno = ERANGE; + return NULL; + } #if 0 if (GetCurrentDirectory (MAXPATHLEN, dir) > 0) return dir; @@ -1528,6 +1544,50 @@ is_unc_volume (const char *filename) return 1; } +/* Emulate the Posix unsetenv. */ +int +unsetenv (const char *name) +{ + char *var; + size_t name_len; + int retval; + + if (name == NULL || *name == '\0' || strchr (name, '=') != NULL) + { + errno = EINVAL; + return -1; + } + name_len = strlen (name); + /* MS docs says an environment variable cannot be longer than 32K. */ + if (name_len > 32767) + { + errno = ENOMEM; + return 0; + } + /* It is safe to use 'alloca' with 32K size, since the stack is at + least 2MB, and we set it to 8MB in the link command line. */ + var = alloca (name_len + 2); + var[name_len++] = '='; + var[name_len] = '\0'; + return _putenv (var); +} + +/* MS _putenv doesn't support removing a variable when the argument + does not include the '=' character, so we fix that here. */ +int +sys_putenv (char *str) +{ + const char *const name_end = strchr (str, '='); + + if (name_end == NULL) + { + /* Remove the variable from the environment. */ + return unsetenv (str); + } + + return _putenv (str); +} + #define REG_ROOT "SOFTWARE\\GNU\\Emacs" LPBYTE @@ -1606,7 +1666,7 @@ init_environment (char ** argv) see if it succeeds. But I think that's too much to ask. */ /* MSVCRT's _access crashes with D_OK. */ - if (tmp && sys_access (tmp, D_OK) == 0) + if (tmp && faccessat (AT_FDCWD, tmp, D_OK, AT_EACCESS) == 0) { char * var = alloca (strlen (tmp) + 8); sprintf (var, "TMPDIR=%s", tmp); @@ -1628,7 +1688,6 @@ init_environment (char ** argv) LPBYTE lpval; DWORD dwType; char locale_name[32]; - struct stat ignored; char default_home[MAX_PATH]; int appdata = 0; @@ -1669,7 +1728,7 @@ init_environment (char ** argv) /* For backwards compatibility, check if a .emacs file exists in C:/ If not, then we can try to default to the appdata directory under the user's profile, which is more likely to be writable. */ - if (stat ("C:/.emacs", &ignored) < 0) + if (!check_existing ("C:/.emacs")) { HRESULT profile_result; /* Dynamically load ShGetFolderPath, as it won't exist on versions @@ -1828,7 +1887,7 @@ init_environment (char ** argv) memcpy (*envp, "COMSPEC=", 8); } - /* Remember the initial working directory for getwd. */ + /* Remember the initial working directory for getcwd. */ /* FIXME: Do we need to resolve possible symlinks in startup_dir? Does it matter anywhere in Emacs? */ if (!GetCurrentDirectory (MAXPATHLEN, startup_dir)) @@ -2441,7 +2500,7 @@ is_exec (const char * name) and readdir. We can't use the procedures supplied in sysdep.c, so we provide them here. */ -struct direct dir_static; /* simulated directory contents */ +struct dirent dir_static; /* simulated directory contents */ static HANDLE dir_find_handle = INVALID_HANDLE_VALUE; static int dir_is_fat; static char dir_pathname[MAXPATHLEN+1]; @@ -2511,7 +2570,7 @@ closedir (DIR *dirp) xfree ((char *) dirp); } -struct direct * +struct dirent * readdir (DIR *dirp) { int downcase = !NILP (Vw32_downcase_file_names); @@ -2565,7 +2624,7 @@ readdir (DIR *dirp) downcase = 1; /* 8+3 aliases are returned in all caps */ } dir_static.d_namlen = strlen (dir_static.d_name); - dir_static.d_reclen = sizeof (struct direct) - MAXNAMLEN + 3 + + dir_static.d_reclen = sizeof (struct dirent) - MAXNAMLEN + 3 + dir_static.d_namlen - dir_static.d_namlen % 4; /* If the file name in cFileName[] includes `?' characters, it means @@ -2718,16 +2777,20 @@ logon_network_drive (const char *path) WNetAddConnection2 (&resource, NULL, NULL, CONNECT_INTERACTIVE); } -/* Shadow some MSVC runtime functions to map requests for long filenames - to reasonable short names if necessary. This was originally added to - permit running Emacs on NT 3.1 on a FAT partition, which doesn't support - long file names. */ - +/* Emulate faccessat(2). */ int -sys_access (const char * path, int mode) +faccessat (int dirfd, const char * path, int mode, int flags) { DWORD attributes; + if (dirfd != AT_FDCWD + && !(IS_DIRECTORY_SEP (path[0]) + || IS_DEVICE_SEP (path[1]))) + { + errno = EBADF; + return -1; + } + /* MSVCRT implementation of 'access' doesn't recognize D_OK, and its newer versions blow up when passed D_OK. */ path = map_w32_filename (path, NULL); @@ -2735,7 +2798,8 @@ sys_access (const char * path, int mode) to get the attributes of its target file. Note: any symlinks in PATH elements other than the last one are transparently resolved by GetFileAttributes below. */ - if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0) + if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0 + && (flags & AT_SYMLINK_NOFOLLOW) == 0) path = chase_symlinks (path); if ((attributes = GetFileAttributes (path)) == -1) @@ -2767,7 +2831,8 @@ sys_access (const char * path, int mode) } return -1; } - if ((mode & X_OK) != 0 && !is_exec (path)) + if ((mode & X_OK) != 0 + && !(is_exec (path) || (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0)) { errno = EACCES; return -1; @@ -2785,6 +2850,11 @@ sys_access (const char * path, int mode) return 0; } +/* Shadow some MSVC runtime functions to map requests for long filenames + to reasonable short names if necessary. This was originally added to + permit running Emacs on NT 3.1 on a FAT partition, which doesn't support + long file names. */ + int sys_chdir (const char * path) { @@ -2970,7 +3040,7 @@ sys_mktemp (char * template) { int save_errno = errno; p[0] = first_char[i]; - if (sys_access (template, 0) < 0) + if (faccessat (AT_FDCWD, template, F_OK, AT_EACCESS) < 0) { errno = save_errno; return template; @@ -3952,8 +4022,12 @@ utime (const char *name, struct utimbuf *times) } /* Need write access to set times. */ - fh = CreateFile (name, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, - 0, OPEN_EXISTING, 0, NULL); + fh = CreateFile (name, FILE_WRITE_ATTRIBUTES, + /* If NAME specifies a directory, FILE_SHARE_DELETE + allows other processes to delete files inside it, + while we have the directory open. */ + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); if (fh != INVALID_HANDLE_VALUE) { convert_from_time_t (times->actime, &atime); @@ -4017,7 +4091,7 @@ symlink (char const *filename, char const *linkname) { /* Non-absolute FILENAME is understood as being relative to LINKNAME's directory. We need to prepend that directory to - FILENAME to get correct results from sys_access below, since + FILENAME to get correct results from faccessat below, since otherwise it will interpret FILENAME relative to the directory where the Emacs process runs. Note that make-symbolic-link always makes sure LINKNAME is a fully @@ -4031,10 +4105,10 @@ symlink (char const *filename, char const *linkname) strncpy (tem, linkfn, p - linkfn); tem[p - linkfn] = '\0'; strcat (tem, filename); - dir_access = sys_access (tem, D_OK); + dir_access = faccessat (AT_FDCWD, tem, D_OK, AT_EACCESS); } else - dir_access = sys_access (filename, D_OK); + dir_access = faccessat (AT_FDCWD, filename, D_OK, AT_EACCESS); /* Since Windows distinguishes between symlinks to directories and to files, we provide a kludgy feature: if FILENAME doesn't @@ -5849,7 +5923,7 @@ fcntl (int s, int cmd, int options) check_errno (); if (fd_info[s].flags & FILE_SOCKET) { - if (cmd == F_SETFL && options == O_NDELAY) + if (cmd == F_SETFL && options == O_NONBLOCK) { unsigned long nblock = 1; int rc = pfn_ioctlsocket (SOCK_HANDLE (s), FIONBIO, &nblock); @@ -6974,7 +7048,7 @@ emacs_gnutls_pull (gnutls_transport_ptr_t p, void* buf, size_t sz) { int n, sc, err; SELECT_TYPE fdset; - struct timeval timeout; + EMACS_TIME timeout; struct Lisp_Process *process = (struct Lisp_Process *)p; int fd = process->infd; @@ -6990,8 +7064,7 @@ emacs_gnutls_pull (gnutls_transport_ptr_t p, void* buf, size_t sz) if (err == EWOULDBLOCK) { /* Set a small timeout. */ - timeout.tv_sec = 1; - timeout.tv_usec = 0; + timeout = make_emacs_time (1, 0); FD_ZERO (&fdset); FD_SET ((int)fd, &fdset);