X-Git-Url: https://git.hcoop.net/bpt/emacs.git/blobdiff_plain/224f4ec1298e93e4d18bba7ea208b08c75ae3422..e2d8a6f0a229b4ebe26484b892ec4f14888f58b6:/src/w32.c diff --git a/src/w32.c b/src/w32.c index 802403168f..7a39a617ee 100644 --- a/src/w32.c +++ b/src/w32.c @@ -29,10 +29,10 @@ along with GNU Emacs. If not, see . */ #include #include #include +#include /* must be before nt/inc/sys/time.h, for MinGW64 */ #include #include #include -#include /* must include CRT headers *before* config.h */ @@ -65,11 +65,13 @@ along with GNU Emacs. If not, see . */ #undef localtime #include "lisp.h" +#include "epaths.h" /* for SHELL */ #include #include -#ifdef __GNUC__ +/* MinGW64 (_W64) defines these in its _mingw.h. */ +#if defined(__GNUC__) && !defined(_W64) #define _ANONYMOUS_UNION #define _ANONYMOUS_STRUCT #endif @@ -96,6 +98,7 @@ typedef struct _MEMORY_STATUS_EX { #ifndef _MSC_VER #include #endif +#if _WIN32_WINNT < 0x0500 #if !defined (__MINGW32__) || __W32API_MAJOR_VERSION < 3 || (__W32API_MAJOR_VERSION == 3 && __W32API_MINOR_VERSION < 15) /* This either is not in psapi.h or guarded by higher value of _WIN32_WINNT than what we use. w32api supplied with MinGW 3.15 @@ -114,15 +117,25 @@ typedef struct _PROCESS_MEMORY_COUNTERS_EX { SIZE_T PrivateUsage; } PROCESS_MEMORY_COUNTERS_EX,*PPROCESS_MEMORY_COUNTERS_EX; #endif +#endif #include #include +#include -#ifdef _MSC_VER -/* 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. */ +#include + +/* This is not in MinGW's sddl.h (but they are in MSVC headers), so we + define them by hand if not already defined. */ +#ifndef SDDL_REVISION_1 +#define SDDL_REVISION_1 1 +#endif /* SDDL_REVISION_1 */ + +#if defined(_MSC_VER) || defined(_W64) +/* MSVC and MinGW64 don'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; @@ -162,9 +175,12 @@ typedef struct _REPARSE_DATA_BUFFER { #ifndef CTL_CODE #define CTL_CODE(t,f,m,a) (((t)<<16)|((a)<<14)|((f)<<2)|(m)) #endif +/* MinGW64 defines FSCTL_GET_REPARSE_POINT on winioctl.h. */ +#ifndef FSCTL_GET_REPARSE_POINT #define FSCTL_GET_REPARSE_POINT \ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS) #endif +#endif /* TCP connection support. */ #include @@ -187,7 +203,7 @@ typedef struct _REPARSE_DATA_BUFFER { #undef sendto #include "w32.h" -#include "ndir.h" +#include #include "w32common.h" #include "w32heap.h" #include "w32select.h" @@ -257,6 +273,11 @@ static BOOL g_b_init_copy_sid; static BOOL g_b_init_get_native_system_info; static BOOL g_b_init_get_system_times; static BOOL g_b_init_create_symbolic_link; +static BOOL g_b_init_get_security_descriptor_dacl; +static BOOL g_b_init_convert_sd_to_sddl; +static BOOL g_b_init_convert_sddl_to_sd; +static BOOL g_b_init_is_valid_security_descriptor; +static BOOL g_b_init_set_file_security; /* BEGIN: Wrapper functions around OpenProcessToken @@ -286,9 +307,11 @@ GetProcessTimes_Proc get_process_times_fn = NULL; #ifdef _UNICODE const char * const LookupAccountSid_Name = "LookupAccountSidW"; const char * const GetFileSecurity_Name = "GetFileSecurityW"; +const char * const SetFileSecurity_Name = "SetFileSecurityW"; #else const char * const LookupAccountSid_Name = "LookupAccountSidA"; const char * const GetFileSecurity_Name = "GetFileSecurityA"; +const char * const SetFileSecurity_Name = "SetFileSecurityA"; #endif typedef BOOL (WINAPI * LookupAccountSid_Proc) ( LPCTSTR lpSystemName, @@ -318,6 +341,10 @@ typedef BOOL (WINAPI * GetFileSecurity_Proc) ( PSECURITY_DESCRIPTOR pSecurityDescriptor, DWORD nLength, LPDWORD lpnLengthNeeded); +typedef BOOL (WINAPI *SetFileSecurity_Proc) ( + LPCTSTR lpFileName, + SECURITY_INFORMATION SecurityInformation, + PSECURITY_DESCRIPTOR pSecurityDescriptor); typedef BOOL (WINAPI * GetSecurityDescriptorOwner_Proc) ( PSECURITY_DESCRIPTOR pSecurityDescriptor, PSID *pOwner, @@ -326,6 +353,11 @@ typedef BOOL (WINAPI * GetSecurityDescriptorGroup_Proc) ( PSECURITY_DESCRIPTOR pSecurityDescriptor, PSID *pGroup, LPBOOL lpbGroupDefaulted); +typedef BOOL (WINAPI *GetSecurityDescriptorDacl_Proc) ( + PSECURITY_DESCRIPTOR pSecurityDescriptor, + LPBOOL lpbDaclPresent, + PACL *pDacl, + LPBOOL lpbDaclDefaulted); typedef BOOL (WINAPI * IsValidSid_Proc) ( PSID sid); typedef HANDLE (WINAPI * CreateToolhelp32Snapshot_Proc) ( @@ -376,6 +408,18 @@ typedef BOOLEAN (WINAPI *CreateSymbolicLink_Proc) ( LPTSTR lpSymlinkFileName, LPTSTR lpTargetFileName, DWORD dwFlags); +typedef BOOL (WINAPI *ConvertStringSecurityDescriptorToSecurityDescriptor_Proc) ( + LPCTSTR StringSecurityDescriptor, + DWORD StringSDRevision, + PSECURITY_DESCRIPTOR *SecurityDescriptor, + PULONG SecurityDescriptorSize); +typedef BOOL (WINAPI *ConvertSecurityDescriptorToStringSecurityDescriptor_Proc) ( + PSECURITY_DESCRIPTOR SecurityDescriptor, + DWORD RequestedStringSDRevision, + SECURITY_INFORMATION SecurityInformation, + LPTSTR *StringSecurityDescriptor, + PULONG StringSecurityDescriptorLen); +typedef BOOL (WINAPI *IsValidSecurityDescriptor_Proc) (PSECURITY_DESCRIPTOR); /* ** A utility function ** */ static BOOL @@ -621,6 +665,7 @@ get_file_security (LPCTSTR lpFileName, HMODULE hm_advapi32 = NULL; if (is_windows_9x () == TRUE) { + errno = ENOTSUP; return FALSE; } if (g_b_init_get_file_security == 0) @@ -633,6 +678,7 @@ get_file_security (LPCTSTR lpFileName, } if (s_pfn_Get_File_Security == NULL) { + errno = ENOTSUP; return FALSE; } return (s_pfn_Get_File_Security (lpFileName, RequestedInformation, @@ -640,6 +686,35 @@ get_file_security (LPCTSTR lpFileName, lpnLengthNeeded)); } +static BOOL WINAPI +set_file_security (LPCTSTR lpFileName, + SECURITY_INFORMATION SecurityInformation, + PSECURITY_DESCRIPTOR pSecurityDescriptor) +{ + static SetFileSecurity_Proc s_pfn_Set_File_Security = NULL; + HMODULE hm_advapi32 = NULL; + if (is_windows_9x () == TRUE) + { + errno = ENOTSUP; + return FALSE; + } + if (g_b_init_set_file_security == 0) + { + g_b_init_set_file_security = 1; + hm_advapi32 = LoadLibrary ("Advapi32.dll"); + s_pfn_Set_File_Security = + (SetFileSecurity_Proc) GetProcAddress ( + hm_advapi32, SetFileSecurity_Name); + } + if (s_pfn_Set_File_Security == NULL) + { + errno = ENOTSUP; + return FALSE; + } + return (s_pfn_Set_File_Security (lpFileName, SecurityInformation, + pSecurityDescriptor)); +} + static BOOL WINAPI get_security_descriptor_owner (PSECURITY_DESCRIPTOR pSecurityDescriptor, PSID *pOwner, @@ -649,6 +724,7 @@ get_security_descriptor_owner (PSECURITY_DESCRIPTOR pSecurityDescriptor, HMODULE hm_advapi32 = NULL; if (is_windows_9x () == TRUE) { + errno = ENOTSUP; return FALSE; } if (g_b_init_get_security_descriptor_owner == 0) @@ -661,6 +737,7 @@ get_security_descriptor_owner (PSECURITY_DESCRIPTOR pSecurityDescriptor, } if (s_pfn_Get_Security_Descriptor_Owner == NULL) { + errno = ENOTSUP; return FALSE; } return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor, pOwner, @@ -676,6 +753,7 @@ get_security_descriptor_group (PSECURITY_DESCRIPTOR pSecurityDescriptor, HMODULE hm_advapi32 = NULL; if (is_windows_9x () == TRUE) { + errno = ENOTSUP; return FALSE; } if (g_b_init_get_security_descriptor_group == 0) @@ -688,12 +766,44 @@ get_security_descriptor_group (PSECURITY_DESCRIPTOR pSecurityDescriptor, } if (s_pfn_Get_Security_Descriptor_Group == NULL) { + errno = ENOTSUP; return FALSE; } return (s_pfn_Get_Security_Descriptor_Group (pSecurityDescriptor, pGroup, lpbGroupDefaulted)); } +static BOOL WINAPI +get_security_descriptor_dacl (PSECURITY_DESCRIPTOR pSecurityDescriptor, + LPBOOL lpbDaclPresent, + PACL *pDacl, + LPBOOL lpbDaclDefaulted) +{ + static GetSecurityDescriptorDacl_Proc s_pfn_Get_Security_Descriptor_Dacl = NULL; + HMODULE hm_advapi32 = NULL; + if (is_windows_9x () == TRUE) + { + errno = ENOTSUP; + return FALSE; + } + if (g_b_init_get_security_descriptor_dacl == 0) + { + g_b_init_get_security_descriptor_dacl = 1; + hm_advapi32 = LoadLibrary ("Advapi32.dll"); + s_pfn_Get_Security_Descriptor_Dacl = + (GetSecurityDescriptorDacl_Proc) GetProcAddress ( + hm_advapi32, "GetSecurityDescriptorDacl"); + } + if (s_pfn_Get_Security_Descriptor_Dacl == NULL) + { + errno = ENOTSUP; + return FALSE; + } + return (s_pfn_Get_Security_Descriptor_Dacl (pSecurityDescriptor, + lpbDaclPresent, pDacl, + lpbDaclDefaulted)); +} + static BOOL WINAPI is_valid_sid (PSID sid) { @@ -888,6 +998,120 @@ create_symbolic_link (LPTSTR lpSymlinkFilename, } return retval; } + +static BOOL WINAPI +is_valid_security_descriptor (PSECURITY_DESCRIPTOR pSecurityDescriptor) +{ + static IsValidSecurityDescriptor_Proc s_pfn_Is_Valid_Security_Descriptor_Proc = NULL; + + if (is_windows_9x () == TRUE) + { + errno = ENOTSUP; + return FALSE; + } + + if (g_b_init_is_valid_security_descriptor == 0) + { + g_b_init_is_valid_security_descriptor = 1; + s_pfn_Is_Valid_Security_Descriptor_Proc = + (IsValidSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"), + "IsValidSecurityDescriptor"); + } + if (s_pfn_Is_Valid_Security_Descriptor_Proc == NULL) + { + errno = ENOTSUP; + return FALSE; + } + + return s_pfn_Is_Valid_Security_Descriptor_Proc (pSecurityDescriptor); +} + +static BOOL WINAPI +convert_sd_to_sddl (PSECURITY_DESCRIPTOR SecurityDescriptor, + DWORD RequestedStringSDRevision, + SECURITY_INFORMATION SecurityInformation, + LPTSTR *StringSecurityDescriptor, + PULONG StringSecurityDescriptorLen) +{ + static ConvertSecurityDescriptorToStringSecurityDescriptor_Proc s_pfn_Convert_SD_To_SDDL = NULL; + BOOL retval; + + if (is_windows_9x () == TRUE) + { + errno = ENOTSUP; + return FALSE; + } + + if (g_b_init_convert_sd_to_sddl == 0) + { + g_b_init_convert_sd_to_sddl = 1; +#ifdef _UNICODE + s_pfn_Convert_SD_To_SDDL = + (ConvertSecurityDescriptorToStringSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"), + "ConvertSecurityDescriptorToStringSecurityDescriptorW"); +#else + s_pfn_Convert_SD_To_SDDL = + (ConvertSecurityDescriptorToStringSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"), + "ConvertSecurityDescriptorToStringSecurityDescriptorA"); +#endif + } + if (s_pfn_Convert_SD_To_SDDL == NULL) + { + errno = ENOTSUP; + return FALSE; + } + + retval = s_pfn_Convert_SD_To_SDDL (SecurityDescriptor, + RequestedStringSDRevision, + SecurityInformation, + StringSecurityDescriptor, + StringSecurityDescriptorLen); + + return retval; +} + +static BOOL WINAPI +convert_sddl_to_sd (LPCTSTR StringSecurityDescriptor, + DWORD StringSDRevision, + PSECURITY_DESCRIPTOR *SecurityDescriptor, + PULONG SecurityDescriptorSize) +{ + static ConvertStringSecurityDescriptorToSecurityDescriptor_Proc s_pfn_Convert_SDDL_To_SD = NULL; + BOOL retval; + + if (is_windows_9x () == TRUE) + { + errno = ENOTSUP; + return FALSE; + } + + if (g_b_init_convert_sddl_to_sd == 0) + { + g_b_init_convert_sddl_to_sd = 1; +#ifdef _UNICODE + s_pfn_Convert_SDDL_To_SD = + (ConvertStringSecurityDescriptorToSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"), + "ConvertStringSecurityDescriptorToSecurityDescriptorW"); +#else + s_pfn_Convert_SDDL_To_SD = + (ConvertStringSecurityDescriptorToSecurityDescriptor_Proc)GetProcAddress (GetModuleHandle ("Advapi32.dll"), + "ConvertStringSecurityDescriptorToSecurityDescriptorA"); +#endif + } + if (s_pfn_Convert_SDDL_To_SD == NULL) + { + errno = ENOTSUP; + return FALSE; + } + + retval = s_pfn_Convert_SDDL_To_SD (StringSecurityDescriptor, + StringSDRevision, + SecurityDescriptor, + SecurityDescriptorSize); + + return retval; +} + /* Return 1 if P is a valid pointer to an object of size SIZE. Return @@ -916,8 +1140,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; @@ -1371,12 +1605,17 @@ max_filename_mbslen (void) case path name components to lower case. */ static void -normalize_filename (register char *fp, char path_sep) +normalize_filename (register char *fp, char path_sep, int multibyte) { char sep; char *elem, *p2; int dbcs_p = max_filename_mbslen () > 1; + /* Multibyte file names are in the Emacs internal representation, so + we can traverse them by bytes with no problems. */ + if (multibyte) + dbcs_p = 0; + /* Always lower-case drive letters a-z, even if the filesystem preserves case in filenames. This is so filenames can be compared by string comparison @@ -1393,7 +1632,7 @@ normalize_filename (register char *fp, char path_sep) fp += 2; } - if (NILP (Vw32_downcase_file_names)) + if (multibyte || NILP (Vw32_downcase_file_names)) { while (*fp) { @@ -1441,18 +1680,20 @@ normalize_filename (register char *fp, char path_sep) } while (*fp); } -/* Destructively turn backslashes into slashes. */ +/* Destructively turn backslashes into slashes. MULTIBYTE non-zero + means the file name is a multibyte string in Emacs's internal + representation. */ void -dostounix_filename (register char *p) +dostounix_filename (register char *p, int multibyte) { - normalize_filename (p, '/'); + normalize_filename (p, '/', multibyte); } /* Destructively turn slashes into backslashes. */ void unixtodos_filename (register char *p) { - normalize_filename (p, '\\'); + normalize_filename (p, '\\', 0); } /* Remove all CR's that are followed by a LF. @@ -1616,6 +1857,51 @@ 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); + strncpy (var, name, name_len); + 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 @@ -1694,7 +1980,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); @@ -1733,7 +2019,7 @@ init_environment (char ** argv) {"PRELOAD_WINSOCK", NULL}, {"emacs_dir", "C:/emacs"}, {"EMACSLOADPATH", NULL}, - {"SHELL", "%emacs_dir%/bin/cmdproxy.exe"}, + {"SHELL", "cmdproxy.exe"}, /* perhaps it is somewhere on PATH */ {"EMACSDATA", NULL}, {"EMACSPATH", NULL}, {"INFOPATH", NULL}, @@ -1809,9 +2095,12 @@ init_environment (char ** argv) emacs_abort (); *p = 0; - if ((p = _mbsrchr (modname, '\\')) && xstrcasecmp (p, "\\bin") == 0) + if ((p = _mbsrchr (modname, '\\')) + /* From bin means installed Emacs, from src means uninstalled. */ + && (xstrcasecmp (p, "\\bin") == 0 || xstrcasecmp (p, "\\src") == 0)) { char buf[SET_ENV_BUF_SIZE]; + int within_build_tree = xstrcasecmp (p, "\\src") == 0; *p = 0; for (p = modname; *p; p = CharNext (p)) @@ -1819,6 +2108,15 @@ init_environment (char ** argv) _snprintf (buf, sizeof (buf)-1, "emacs_dir=%s", modname); _putenv (strdup (buf)); + /* If we are running from the Posix-like build tree, define + SHELL to point to our own cmdproxy. The loop below will + then disregard PATH_EXEC and the default value. */ + if (within_build_tree) + { + _snprintf (buf, sizeof (buf) - 1, + "SHELL=%s/nt/cmdproxy.exe", modname); + _putenv (strdup (buf)); + } } /* Handle running emacs from the build directory: src/oo-spd/i386/ */ @@ -1854,16 +2152,60 @@ init_environment (char ** argv) if (!getenv (env_vars[i].name)) { int dont_free = 0; + char bufc[SET_ENV_BUF_SIZE]; if ((lpval = w32_get_resource (env_vars[i].name, &dwType)) == NULL /* Also ignore empty environment variables. */ || *lpval == 0) { xfree (lpval); - lpval = env_vars[i].def_value; - dwType = REG_EXPAND_SZ; dont_free = 1; - if (!strcmp (env_vars[i].name, "HOME") && !appdata) + if (strcmp (env_vars[i].name, "SHELL") == 0) + { + /* Look for cmdproxy.exe in every directory in + PATH_EXEC. FIXME: This does not find cmdproxy + in nt/ when we run uninstalled. */ + char fname[MAX_PATH]; + const char *pstart = PATH_EXEC, *pend; + + do { + pend = _mbschr (pstart, ';'); + if (!pend) + pend = pstart + strlen (pstart); + /* Be defensive against series of ;;; characters. */ + if (pend > pstart) + { + strncpy (fname, pstart, pend - pstart); + fname[pend - pstart] = '/'; + strcpy (&fname[pend - pstart + 1], "cmdproxy.exe"); + ExpandEnvironmentStrings ((LPSTR) fname, bufc, + sizeof (bufc)); + if (check_existing (bufc)) + { + lpval = bufc; + dwType = REG_SZ; + break; + } + } + if (*pend) + pstart = pend + 1; + else + pstart = pend; + if (!*pstart) + { + /* If not found in any directory, use the + default as the last resort. */ + lpval = env_vars[i].def_value; + dwType = REG_EXPAND_SZ; + } + } while (*pstart); + } + else + { + lpval = env_vars[i].def_value; + dwType = REG_EXPAND_SZ; + } + if (strcmp (env_vars[i].name, "HOME") == 0 && !appdata) Vdelayed_warnings_list = Fcons (listn (CONSTYPE_HEAP, 2, intern ("initialization"), @@ -1915,7 +2257,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)) @@ -1950,7 +2292,7 @@ emacs_root_dir (void) emacs_abort (); strcpy (root_dir, p); root_dir[parse_root (root_dir, NULL)] = '\0'; - dostounix_filename (root_dir); + dostounix_filename (root_dir, 0); return root_dir; } @@ -2109,8 +2451,8 @@ get_emacs_configuration_options (void) #include /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */ -void -gettimeofday (struct timeval *tv, struct timezone *tz) +int +gettimeofday (struct timeval *__restrict tv, struct timezone *__restrict tz) { struct _timeb tb; _ftime (&tb); @@ -2128,6 +2470,7 @@ gettimeofday (struct timeval *tv, struct timezone *tz) tz->tz_minuteswest = tb.timezone; /* minutes west of Greenwich */ tz->tz_dsttime = tb.dstflag; /* type of dst correction */ } + return 0; } /* Emulate fdutimens. */ @@ -2539,7 +2882,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]; @@ -2553,7 +2896,7 @@ static char *read_unc_volume (HANDLE, char *, int); static void close_unc_volume (HANDLE); DIR * -opendir (char *filename) +opendir (const char *filename) { DIR *dirp; @@ -2609,7 +2952,7 @@ closedir (DIR *dirp) xfree ((char *) dirp); } -struct direct * +struct dirent * readdir (DIR *dirp) { int downcase = !NILP (Vw32_downcase_file_names); @@ -2675,7 +3018,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 @@ -2849,16 +3192,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); @@ -2866,7 +3213,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) @@ -2898,7 +3246,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; @@ -2916,6 +3265,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) { @@ -2929,14 +3283,6 @@ sys_chmod (const char * path, int mode) return _chmod (path, mode); } -int -sys_chown (const char *path, uid_t owner, gid_t group) -{ - if (sys_chmod (path, S_IREAD) == -1) /* check if file exists */ - return -1; - return 0; -} - int sys_creat (const char * path, int mode) { @@ -3101,7 +3447,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; @@ -3120,20 +3466,27 @@ int sys_open (const char * path, int oflag, int mode) { const char* mpath = map_w32_filename (path, NULL); - /* Try to open file without _O_CREAT, to be able to write to hidden - and system files. Force all file handles to be - non-inheritable. */ - int res = _open (mpath, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode); + int res = -1; + + /* If possible, try to open file without _O_CREAT, to be able to + write to existing hidden and system files. Force all file + handles to be non-inheritable. */ + if ((oflag & (_O_CREAT | _O_EXCL)) != (_O_CREAT | _O_EXCL)) + res = _open (mpath, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode); if (res < 0) res = _open (mpath, oflag | _O_NOINHERIT, mode); - if (res >= 0 && res < MAXDESC) - fd_info[res].flags = 0; return res; } int -sys_rename (const char * oldname, const char * newname) +fchmod (int fd, mode_t mode) +{ + return 0; +} + +int +sys_rename_replace (const char *oldname, const char *newname, BOOL force) { BOOL result; char temp[MAX_PATH]; @@ -3189,7 +3542,7 @@ sys_rename (const char * oldname, const char * newname) return -1; } - /* Emulate Unix behavior - newname is deleted if it already exists + /* If FORCE, emulate Unix behavior - newname is deleted if it already exists (at least if it is a file; don't do this for directories). Since we mustn't do this if we are just changing the case of the @@ -3207,7 +3560,7 @@ sys_rename (const char * oldname, const char * newname) result = rename (temp, newname); - if (result < 0) + if (result < 0 && force) { DWORD w32err = GetLastError (); @@ -3246,6 +3599,12 @@ sys_rename (const char * oldname, const char * newname) return result; } +int +sys_rename (char const *old, char const *new) +{ + return sys_rename_replace (old, new, TRUE); +} + int sys_rmdir (const char * path) { @@ -3494,7 +3853,6 @@ static int get_name_and_id (PSECURITY_DESCRIPTOR psd, unsigned *id, char *nm, int what) { PSID sid = NULL; - char machine[MAX_COMPUTERNAME_LENGTH+1]; BOOL dflt; SID_NAME_USE ignore; char name[UNLEN+1]; @@ -3582,6 +3940,10 @@ is_slow_fs (const char *name) return !(devtype == DRIVE_FIXED || devtype == DRIVE_RAMDISK); } +/* If this is non-zero, the caller wants accurate information about + file's owner and group, which could be expensive to get. */ +int w32_stat_get_owner_group; + /* MSVC stat function can't cope with UNC names and has other bugs, so replace it with our own. This also allows us to calculate consistent inode values and owner/group without hacks in the main Emacs code. */ @@ -3754,6 +4116,7 @@ stat_worker (const char * path, struct stat * buf, int follow_symlinks) /* We produce the fallback owner and group data, based on the current user that runs Emacs, in the following cases: + . caller didn't request owner and group info . this is Windows 9X . getting security by handle failed, and we need to produce information for the target of a symlink (this is better @@ -3762,23 +4125,25 @@ stat_worker (const char * path, struct stat * buf, int follow_symlinks) If getting security by handle fails, and we don't need to resolve symlinks, we try getting security by name. */ - if (is_windows_9x () != TRUE) - psd = get_file_security_desc_by_handle (fh); - if (psd) - { - get_file_owner_and_group (psd, buf); - LocalFree (psd); - } - else if (is_windows_9x () == TRUE) + if (!w32_stat_get_owner_group || is_windows_9x () == TRUE) get_file_owner_and_group (NULL, buf); - else if (!(is_a_symlink && follow_symlinks)) + else { - psd = get_file_security_desc_by_name (name); - get_file_owner_and_group (psd, buf); - xfree (psd); + psd = get_file_security_desc_by_handle (fh); + if (psd) + { + get_file_owner_and_group (psd, buf); + LocalFree (psd); + } + else if (!(is_a_symlink && follow_symlinks)) + { + psd = get_file_security_desc_by_name (name); + get_file_owner_and_group (psd, buf); + xfree (psd); + } + else + get_file_owner_and_group (NULL, buf); } - else - get_file_owner_and_group (NULL, buf); CloseHandle (fh); } else @@ -3985,6 +4350,30 @@ lstat (const char * path, struct stat * buf) return stat_worker (path, buf, 0); } +int +fstatat (int fd, char const *name, struct stat *st, int flags) +{ + /* Rely on a hack: an open directory is modeled as file descriptor 0. + This is good enough for the current usage in Emacs, but is fragile. + + FIXME: Add proper support for fdopendir, fstatat, readlinkat. + Gnulib does this and can serve as a model. */ + char fullname[MAX_PATH]; + + if (fd != AT_FDCWD) + { + if (_snprintf (fullname, sizeof fullname, "%s/%s", dir_pathname, name) + < 0) + { + errno = ENAMETOOLONG; + return -1; + } + name = fullname; + } + + return stat_worker (name, st, ! (flags & AT_SYMLINK_NOFOLLOW)); +} + /* Provide fstat and utime as well as stat for consistent handling of file timestamps. */ int @@ -4039,13 +4428,23 @@ fstat (int desc, struct stat * buf) else buf->st_ino = fake_inode; - /* Consider files to belong to current user. - FIXME: this should use GetSecurityInfo API, but it is only - available for _WIN32_WINNT >= 0x501. */ - buf->st_uid = dflt_passwd.pw_uid; - buf->st_gid = dflt_passwd.pw_gid; - strcpy (buf->st_uname, dflt_passwd.pw_name); - strcpy (buf->st_gname, dflt_group.gr_name); + /* If the caller so requested, get the true file owner and group. + Otherwise, consider the file to belong to the current user. */ + if (!w32_stat_get_owner_group || is_windows_9x () == TRUE) + get_file_owner_and_group (NULL, buf); + else + { + PSECURITY_DESCRIPTOR psd = NULL; + + psd = get_file_security_desc_by_handle (fh); + if (psd) + { + get_file_owner_and_group (psd, buf); + LocalFree (psd); + } + else + get_file_owner_and_group (NULL, buf); + } buf->st_dev = info.dwVolumeSerialNumber; buf->st_rdev = info.dwVolumeSerialNumber; @@ -4174,7 +4573,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 @@ -4201,10 +4600,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 @@ -4398,7 +4797,7 @@ readlink (const char *name, char *buf, size_t buf_size) errno = EINVAL; else { - /* Copy the link target name, in wide characters, fro + /* Copy the link target name, in wide characters, from reparse_data, then convert it to multibyte encoding in the current locale's codepage. */ WCHAR *lwname; @@ -4517,6 +4916,28 @@ readlink (const char *name, char *buf, size_t buf_size) return retval; } +ssize_t +readlinkat (int fd, char const *name, char *buffer, + size_t buffer_size) +{ + /* Rely on a hack: an open directory is modeled as file descriptor 0, + as in fstatat. FIXME: Add proper support for readlinkat. */ + char fullname[MAX_PATH]; + + if (fd != AT_FDCWD) + { + if (_snprintf (fullname, sizeof fullname, "%s/%s", dir_pathname, name) + < 0) + { + errno = ENAMETOOLONG; + return -1; + } + name = fullname; + } + + return readlink (name, buffer, buffer_size); +} + /* If FILE is a symlink, return its target (stored in a static buffer); otherwise return FILE. @@ -4617,6 +5038,245 @@ chase_symlinks (const char *file) return target; } + +/* Posix ACL emulation. */ + +int +acl_valid (acl_t acl) +{ + return is_valid_security_descriptor ((PSECURITY_DESCRIPTOR)acl) ? 0 : -1; +} + +char * +acl_to_text (acl_t acl, ssize_t *size) +{ + LPTSTR str_acl; + SECURITY_INFORMATION flags = + OWNER_SECURITY_INFORMATION | + GROUP_SECURITY_INFORMATION | + DACL_SECURITY_INFORMATION; + char *retval = NULL; + ULONG local_size; + int e = errno; + + errno = 0; + + if (convert_sd_to_sddl ((PSECURITY_DESCRIPTOR)acl, SDDL_REVISION_1, flags, &str_acl, &local_size)) + { + errno = e; + /* We don't want to mix heaps, so we duplicate the string in our + heap and free the one allocated by the API. */ + retval = xstrdup (str_acl); + if (size) + *size = local_size; + LocalFree (str_acl); + } + else if (errno != ENOTSUP) + errno = EINVAL; + + return retval; +} + +acl_t +acl_from_text (const char *acl_str) +{ + PSECURITY_DESCRIPTOR psd, retval = NULL; + ULONG sd_size; + int e = errno; + + errno = 0; + + if (convert_sddl_to_sd (acl_str, SDDL_REVISION_1, &psd, &sd_size)) + { + errno = e; + retval = xmalloc (sd_size); + memcpy (retval, psd, sd_size); + LocalFree (psd); + } + else if (errno != ENOTSUP) + errno = EINVAL; + + return retval; +} + +int +acl_free (void *ptr) +{ + xfree (ptr); + return 0; +} + +acl_t +acl_get_file (const char *fname, acl_type_t type) +{ + PSECURITY_DESCRIPTOR psd = NULL; + const char *filename; + + if (type == ACL_TYPE_ACCESS) + { + DWORD sd_len, err; + SECURITY_INFORMATION si = + OWNER_SECURITY_INFORMATION | + GROUP_SECURITY_INFORMATION | + DACL_SECURITY_INFORMATION ; + int e = errno; + + filename = map_w32_filename (fname, NULL); + if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0) + fname = chase_symlinks (filename); + else + fname = filename; + + errno = 0; + if (!get_file_security (fname, si, psd, 0, &sd_len) + && errno != ENOTSUP) + { + err = GetLastError (); + if (err == ERROR_INSUFFICIENT_BUFFER) + { + psd = xmalloc (sd_len); + if (!get_file_security (fname, si, psd, sd_len, &sd_len)) + { + xfree (psd); + errno = EIO; + psd = NULL; + } + } + else if (err == ERROR_FILE_NOT_FOUND + || err == ERROR_PATH_NOT_FOUND) + errno = ENOENT; + else + errno = EIO; + } + else if (!errno) + errno = e; + } + else if (type != ACL_TYPE_DEFAULT) + errno = EINVAL; + + return psd; +} + +int +acl_set_file (const char *fname, acl_type_t type, acl_t acl) +{ + TOKEN_PRIVILEGES old1, old2; + DWORD err; + int st = 0, retval = -1; + SECURITY_INFORMATION flags = 0; + PSID psid; + PACL pacl; + BOOL dflt; + BOOL dacl_present; + int e; + const char *filename; + + if (acl_valid (acl) != 0 + || (type != ACL_TYPE_DEFAULT && type != ACL_TYPE_ACCESS)) + { + errno = EINVAL; + return -1; + } + + if (type == ACL_TYPE_DEFAULT) + { + errno = ENOSYS; + return -1; + } + + filename = map_w32_filename (fname, NULL); + if ((volume_info.flags & FILE_SUPPORTS_REPARSE_POINTS) != 0) + fname = chase_symlinks (filename); + else + fname = filename; + + if (get_security_descriptor_owner ((PSECURITY_DESCRIPTOR)acl, &psid, &dflt) + && psid) + flags |= OWNER_SECURITY_INFORMATION; + if (get_security_descriptor_group ((PSECURITY_DESCRIPTOR)acl, &psid, &dflt) + && psid) + flags |= GROUP_SECURITY_INFORMATION; + if (get_security_descriptor_dacl ((PSECURITY_DESCRIPTOR)acl, &dacl_present, + &pacl, &dflt) + && dacl_present) + flags |= DACL_SECURITY_INFORMATION; + if (!flags) + return 0; + + /* According to KB-245153, setting the owner will succeed if either: + (1) the caller is the user who will be the new owner, and has the + SE_TAKE_OWNERSHIP privilege, or + (2) the caller has the SE_RESTORE privilege, in which case she can + set any valid user or group as the owner + + We request below both SE_TAKE_OWNERSHIP and SE_RESTORE + privileges, and disregard any failures in obtaining them. If + these privileges cannot be obtained, and do not already exist in + the calling thread's security token, this function could fail + with EPERM. */ + if (enable_privilege (SE_TAKE_OWNERSHIP_NAME, TRUE, &old1)) + st++; + if (enable_privilege (SE_RESTORE_NAME, TRUE, &old2)) + st++; + + e = errno; + errno = 0; + if (!set_file_security ((char *)fname, flags, (PSECURITY_DESCRIPTOR)acl)) + { + err = GetLastError (); + + if (errno == ENOTSUP) + ; + else if (err == ERROR_INVALID_OWNER + || err == ERROR_NOT_ALL_ASSIGNED + || err == ERROR_ACCESS_DENIED) + { + /* Maybe the requested ACL and the one the file already has + are identical, in which case we can silently ignore the + failure. (And no, Windows doesn't.) */ + acl_t current_acl = acl_get_file (fname, ACL_TYPE_ACCESS); + + errno = EPERM; + if (current_acl) + { + char *acl_from = acl_to_text (current_acl, NULL); + char *acl_to = acl_to_text (acl, NULL); + + if (acl_from && acl_to && xstrcasecmp (acl_from, acl_to) == 0) + { + retval = 0; + errno = e; + } + if (acl_from) + acl_free (acl_from); + if (acl_to) + acl_free (acl_to); + acl_free (current_acl); + } + } + else if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND) + errno = ENOENT; + else + errno = EACCES; + } + else + { + retval = 0; + errno = e; + } + + if (st) + { + if (st >= 2) + restore_privilege (&old2); + restore_privilege (&old1); + revert_to_self (); + } + + return retval; +} + + /* MS-Windows version of careadlinkat (cf. ../lib/careadlinkat.c). We have a fixed max size for file names, so we don't need the kind of alloc/malloc/realloc dance the gnulib version does. We also don't @@ -4630,12 +5290,6 @@ careadlinkat (int fd, char const *filename, char linkname[MAX_PATH]; ssize_t link_size; - if (fd != AT_FDCWD) - { - errno = EINVAL; - return NULL; - } - link_size = preadlinkat (fd, filename, linkname, sizeof(linkname)); if (link_size > 0) @@ -4653,14 +5307,6 @@ careadlinkat (int fd, char const *filename, return NULL; } -ssize_t -careadlinkatcwd (int fd, char const *filename, char *buffer, - size_t buffer_size) -{ - (void) fd; - return readlink (filename, buffer, buffer_size); -} - /* Support for browsing other processes and their attributes. See process.c for the Lisp bindings. */ @@ -4998,10 +5644,8 @@ ltime (ULONGLONG time_100ns) { ULONGLONG time_sec = time_100ns / 10000000; int subsec = time_100ns % 10000000; - return list4 (make_number (time_sec >> 16), - make_number (time_sec & 0xffff), - make_number (subsec / 10), - make_number (subsec % 10 * 100000)); + return list4i (time_sec >> 16, time_sec & 0xffff, + subsec / 10, subsec % 10 * 100000); } #define U64_TO_LISP_TIME(time) ltime (time) @@ -5515,35 +6159,39 @@ init_winsock (int load_now) int h_errno = 0; -/* function to set h_errno for compatibility; map winsock error codes to - normal system codes where they overlap (non-overlapping definitions - are already in */ +/* Function to map winsock error codes to errno codes for those errno + code defined in errno.h (errno values not defined by errno.h are + already in nt/inc/sys/socket.h). */ static void set_errno (void) { + int wsa_err; + + h_errno = 0; if (winsock_lib == NULL) - h_errno = EINVAL; + wsa_err = EINVAL; else - h_errno = pfn_WSAGetLastError (); + wsa_err = pfn_WSAGetLastError (); - switch (h_errno) + switch (wsa_err) { - case WSAEACCES: h_errno = EACCES; break; - case WSAEBADF: h_errno = EBADF; break; - case WSAEFAULT: h_errno = EFAULT; break; - case WSAEINTR: h_errno = EINTR; break; - case WSAEINVAL: h_errno = EINVAL; break; - case WSAEMFILE: h_errno = EMFILE; break; - case WSAENAMETOOLONG: h_errno = ENAMETOOLONG; break; - case WSAENOTEMPTY: h_errno = ENOTEMPTY; break; + case WSAEACCES: errno = EACCES; break; + case WSAEBADF: errno = EBADF; break; + case WSAEFAULT: errno = EFAULT; break; + case WSAEINTR: errno = EINTR; break; + case WSAEINVAL: errno = EINVAL; break; + case WSAEMFILE: errno = EMFILE; break; + case WSAENAMETOOLONG: errno = ENAMETOOLONG; break; + case WSAENOTEMPTY: errno = ENOTEMPTY; break; + default: errno = wsa_err; break; } - errno = h_errno; } static void check_errno (void) { - if (h_errno == 0 && winsock_lib != NULL) + h_errno = 0; + if (winsock_lib != NULL) pfn_WSASetLastError (0); } @@ -5655,7 +6303,7 @@ sys_socket (int af, int type, int protocol) if (winsock_lib == NULL) { - h_errno = ENETDOWN; + errno = ENETDOWN; return INVALID_SOCKET; } @@ -5732,6 +6380,7 @@ socket_to_fd (SOCKET s) } } } + eassert (fd < MAXDESC); fd_info[fd].hnd = (HANDLE) s; /* set our own internal flags */ @@ -5760,8 +6409,9 @@ socket_to_fd (SOCKET s) /* clean up */ _close (fd); } + else pfn_closesocket (s); - h_errno = EMFILE; + errno = EMFILE; return -1; } @@ -5770,7 +6420,7 @@ sys_bind (int s, const struct sockaddr * addr, int namelen) { if (winsock_lib == NULL) { - h_errno = ENOTSOCK; + errno = ENOTSOCK; return SOCKET_ERROR; } @@ -5782,7 +6432,7 @@ sys_bind (int s, const struct sockaddr * addr, int namelen) set_errno (); return rc; } - h_errno = ENOTSOCK; + errno = ENOTSOCK; return SOCKET_ERROR; } @@ -5791,7 +6441,7 @@ sys_connect (int s, const struct sockaddr * name, int namelen) { if (winsock_lib == NULL) { - h_errno = ENOTSOCK; + errno = ENOTSOCK; return SOCKET_ERROR; } @@ -5803,7 +6453,7 @@ sys_connect (int s, const struct sockaddr * name, int namelen) set_errno (); return rc; } - h_errno = ENOTSOCK; + errno = ENOTSOCK; return SOCKET_ERROR; } @@ -5832,12 +6482,20 @@ int sys_gethostname (char * name, int namelen) { if (winsock_lib != NULL) - return pfn_gethostname (name, namelen); + { + int retval; + + check_errno (); + retval = pfn_gethostname (name, namelen); + if (retval == SOCKET_ERROR) + set_errno (); + return retval; + } if (namelen > MAX_COMPUTERNAME_LENGTH) return !GetComputerName (name, (DWORD *)&namelen); - h_errno = EFAULT; + errno = EFAULT; return SOCKET_ERROR; } @@ -5845,17 +6503,24 @@ struct hostent * sys_gethostbyname (const char * name) { struct hostent * host; + int h_err = h_errno; if (winsock_lib == NULL) { - h_errno = ENETDOWN; + h_errno = NO_RECOVERY; + errno = ENETDOWN; return NULL; } check_errno (); host = pfn_gethostbyname (name); if (!host) - set_errno (); + { + set_errno (); + h_errno = errno; + } + else + h_errno = h_err; return host; } @@ -5866,7 +6531,7 @@ sys_getservbyname (const char * name, const char * proto) if (winsock_lib == NULL) { - h_errno = ENETDOWN; + errno = ENETDOWN; return NULL; } @@ -5882,7 +6547,7 @@ sys_getpeername (int s, struct sockaddr *addr, int * namelen) { if (winsock_lib == NULL) { - h_errno = ENETDOWN; + errno = ENETDOWN; return SOCKET_ERROR; } @@ -5894,7 +6559,7 @@ sys_getpeername (int s, struct sockaddr *addr, int * namelen) set_errno (); return rc; } - h_errno = ENOTSOCK; + errno = ENOTSOCK; return SOCKET_ERROR; } @@ -5903,7 +6568,7 @@ sys_shutdown (int s, int how) { if (winsock_lib == NULL) { - h_errno = ENETDOWN; + errno = ENETDOWN; return SOCKET_ERROR; } @@ -5915,7 +6580,7 @@ sys_shutdown (int s, int how) set_errno (); return rc; } - h_errno = ENOTSOCK; + errno = ENOTSOCK; return SOCKET_ERROR; } @@ -5924,7 +6589,7 @@ sys_setsockopt (int s, int level, int optname, const void * optval, int optlen) { if (winsock_lib == NULL) { - h_errno = ENETDOWN; + errno = ENETDOWN; return SOCKET_ERROR; } @@ -5937,7 +6602,7 @@ sys_setsockopt (int s, int level, int optname, const void * optval, int optlen) set_errno (); return rc; } - h_errno = ENOTSOCK; + errno = ENOTSOCK; return SOCKET_ERROR; } @@ -5946,7 +6611,7 @@ sys_listen (int s, int backlog) { if (winsock_lib == NULL) { - h_errno = ENETDOWN; + errno = ENETDOWN; return SOCKET_ERROR; } @@ -5960,7 +6625,7 @@ sys_listen (int s, int backlog) fd_info[s].flags |= FILE_LISTEN; return rc; } - h_errno = ENOTSOCK; + errno = ENOTSOCK; return SOCKET_ERROR; } @@ -5969,7 +6634,7 @@ sys_getsockname (int s, struct sockaddr * name, int * namelen) { if (winsock_lib == NULL) { - h_errno = ENETDOWN; + errno = ENETDOWN; return SOCKET_ERROR; } @@ -5981,7 +6646,7 @@ sys_getsockname (int s, struct sockaddr * name, int * namelen) set_errno (); return rc; } - h_errno = ENOTSOCK; + errno = ENOTSOCK; return SOCKET_ERROR; } @@ -5990,7 +6655,7 @@ sys_accept (int s, struct sockaddr * addr, int * addrlen) { if (winsock_lib == NULL) { - h_errno = ENETDOWN; + errno = ENETDOWN; return -1; } @@ -6004,11 +6669,14 @@ sys_accept (int s, struct sockaddr * addr, int * addrlen) else fd = socket_to_fd (t); - fd_info[s].cp->status = STATUS_READ_ACKNOWLEDGED; - ResetEvent (fd_info[s].cp->char_avail); + if (fd >= 0) + { + fd_info[s].cp->status = STATUS_READ_ACKNOWLEDGED; + ResetEvent (fd_info[s].cp->char_avail); + } return fd; } - h_errno = ENOTSOCK; + errno = ENOTSOCK; return -1; } @@ -6018,7 +6686,7 @@ sys_recvfrom (int s, char * buf, int len, int flags, { if (winsock_lib == NULL) { - h_errno = ENETDOWN; + errno = ENETDOWN; return SOCKET_ERROR; } @@ -6030,7 +6698,7 @@ sys_recvfrom (int s, char * buf, int len, int flags, set_errno (); return rc; } - h_errno = ENOTSOCK; + errno = ENOTSOCK; return SOCKET_ERROR; } @@ -6040,7 +6708,7 @@ sys_sendto (int s, const char * buf, int len, int flags, { if (winsock_lib == NULL) { - h_errno = ENETDOWN; + errno = ENETDOWN; return SOCKET_ERROR; } @@ -6052,7 +6720,7 @@ sys_sendto (int s, const char * buf, int len, int flags, set_errno (); return rc; } - h_errno = ENOTSOCK; + errno = ENOTSOCK; return SOCKET_ERROR; } @@ -6063,14 +6731,14 @@ fcntl (int s, int cmd, int options) { if (winsock_lib == NULL) { - h_errno = ENETDOWN; + errno = ENETDOWN; return -1; } 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); @@ -6082,11 +6750,11 @@ fcntl (int s, int cmd, int options) } else { - h_errno = EINVAL; + errno = EINVAL; return SOCKET_ERROR; } } - h_errno = ENOTSOCK; + errno = ENOTSOCK; return SOCKET_ERROR; } @@ -6133,7 +6801,21 @@ sys_close (int fd) winsock_inuse--; /* count open sockets */ } - delete_child (cp); + /* If the process handle is NULL, it's either a socket + or serial connection, or a subprocess that was + already reaped by reap_subprocess, but whose + resources were not yet freed, because its output was + not fully read yet by the time it was reaped. (This + usually happens with async subprocesses whose output + is being read by Emacs.) Otherwise, this process was + not reaped yet, so we set its FD to a negative value + to make sure sys_select will eventually get to + calling the SIGCHLD handler for it, which will then + invoke waitpid and reap_subprocess. */ + if (cp->procinfo.hProcess == NULL) + delete_child (cp); + else + cp->fd = -1; } } } @@ -6209,6 +6891,7 @@ sys_pipe (int * phandles) { _close (phandles[0]); _close (phandles[1]); + errno = EMFILE; rc = -1; } else @@ -6225,7 +6908,8 @@ sys_pipe (int * phandles) } /* Function to do blocking read of one byte, needed to implement - select. It is only allowed on sockets and pipes. */ + select. It is only allowed on communication ports, sockets, or + pipes. */ int _sys_read_ahead (int fd) { @@ -6281,19 +6965,31 @@ _sys_read_ahead (int fd) /* Configure timeouts for blocking read. */ if (!GetCommTimeouts (hnd, &ct)) - return STATUS_READ_ERROR; + { + cp->status = STATUS_READ_ERROR; + return STATUS_READ_ERROR; + } ct.ReadIntervalTimeout = 0; ct.ReadTotalTimeoutMultiplier = 0; ct.ReadTotalTimeoutConstant = 0; if (!SetCommTimeouts (hnd, &ct)) - return STATUS_READ_ERROR; + { + cp->status = STATUS_READ_ERROR; + return STATUS_READ_ERROR; + } if (!ReadFile (hnd, &cp->chr, sizeof (char), (DWORD*) &rc, ovl)) { if (GetLastError () != ERROR_IO_PENDING) - return STATUS_READ_ERROR; + { + cp->status = STATUS_READ_ERROR; + return STATUS_READ_ERROR; + } if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE)) - return STATUS_READ_ERROR; + { + cp->status = STATUS_READ_ERROR; + return STATUS_READ_ERROR; + } } } else if (fd_info[fd].flags & FILE_SOCKET) @@ -6489,7 +7185,7 @@ sys_read (int fd, char * buffer, unsigned int count) pfn_ioctlsocket (SOCK_HANDLE (fd), FIONREAD, &waiting); if (waiting == 0 && nchars == 0) { - h_errno = errno = EWOULDBLOCK; + errno = EWOULDBLOCK; return -1; } @@ -6987,6 +7683,11 @@ globals_of_w32 (void) g_b_init_get_native_system_info = 0; g_b_init_get_system_times = 0; g_b_init_create_symbolic_link = 0; + g_b_init_get_security_descriptor_dacl = 0; + g_b_init_convert_sd_to_sddl = 0; + g_b_init_convert_sddl_to_sd = 0; + g_b_init_is_valid_security_descriptor = 0; + g_b_init_set_file_security = 0; num_of_processors = 0; /* The following sets a handler for shutdown notifications for console apps. This actually applies to Emacs in both console and @@ -6996,6 +7697,9 @@ globals_of_w32 (void) /* "None" is the default group name on standalone workstations. */ strcpy (dflt_group_name, "None"); + + /* Reset, in case it has some value inherited from dump time. */ + w32_stat_get_owner_group = 0; } /* For make-serial-process */ @@ -7193,47 +7897,26 @@ serial_configure (struct Lisp_Process *p, Lisp_Object contact) ssize_t emacs_gnutls_pull (gnutls_transport_ptr_t p, void* buf, size_t sz) { - int n, sc, err; + int n, err; SELECT_TYPE fdset; EMACS_TIME timeout; struct Lisp_Process *process = (struct Lisp_Process *)p; int fd = process->infd; - for (;;) - { - n = sys_read (fd, (char*)buf, sz); + n = sys_read (fd, (char*)buf, sz); - if (n >= 0) - return n; + if (n >= 0) + return n; - err = errno; + err = errno; - if (err == EWOULDBLOCK) - { - /* Set a small timeout. */ - timeout = make_emacs_time (1, 0); - FD_ZERO (&fdset); - FD_SET ((int)fd, &fdset); - - /* Use select with the timeout to poll the selector. */ - sc = select (fd + 1, &fdset, (SELECT_TYPE *)0, (SELECT_TYPE *)0, - &timeout, NULL); - - if (sc > 0) - continue; /* Try again. */ - - /* Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. - Also accept select return 0 as an indicator to EAGAIN. */ - if (sc == 0 || errno == EWOULDBLOCK) - err = EAGAIN; - else - err = errno; /* Other errors are just passed on. */ - } + /* Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */ + if (err == EWOULDBLOCK) + err = EAGAIN; - emacs_gnutls_transport_set_errno (process->gnutls_state, err); + emacs_gnutls_transport_set_errno (process->gnutls_state, err); - return -1; - } + return -1; } ssize_t