#include <ctype.h>
#include <signal.h>
#include <sys/file.h>
+#include <time.h> /* must be before nt/inc/sys/time.h, for MinGW64 */
#include <sys/time.h>
#include <sys/utime.h>
#include <math.h>
-#include <time.h>
/* must include CRT headers *before* config.h */
#include <pwd.h>
#include <grp.h>
-#ifdef __GNUC__
+/* MinGW64 (_W64) defines these in its _mingw.h. */
+#if defined(__GNUC__) && !defined(_W64)
#define _ANONYMOUS_UNION
#define _ANONYMOUS_STRUCT
#endif
#ifndef _MSC_VER
#include <w32api.h>
#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
SIZE_T PrivateUsage;
} PROCESS_MEMORY_COUNTERS_EX,*PPROCESS_MEMORY_COUNTERS_EX;
#endif
+#endif
#include <winioctl.h>
#include <aclapi.h>
+#include <sddl.h>
-#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 <sys/acl.h>
+
+/* 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;
#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 <sys/socket.h>
#undef sendto
#include "w32.h"
-#include "ndir.h"
+#include <dirent.h>
#include "w32common.h"
#include "w32heap.h"
#include "w32select.h"
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
#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,
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,
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) (
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
HMODULE hm_advapi32 = NULL;
if (is_windows_9x () == TRUE)
{
+ errno = ENOTSUP;
return FALSE;
}
if (g_b_init_get_file_security == 0)
}
if (s_pfn_Get_File_Security == NULL)
{
+ errno = ENOTSUP;
return FALSE;
}
return (s_pfn_Get_File_Security (lpFileName, RequestedInformation,
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,
HMODULE hm_advapi32 = NULL;
if (is_windows_9x () == TRUE)
{
+ errno = ENOTSUP;
return FALSE;
}
if (g_b_init_get_security_descriptor_owner == 0)
}
if (s_pfn_Get_Security_Descriptor_Owner == NULL)
{
+ errno = ENOTSUP;
return FALSE;
}
return (s_pfn_Get_Security_Descriptor_Owner (pSecurityDescriptor, pOwner,
HMODULE hm_advapi32 = NULL;
if (is_windows_9x () == TRUE)
{
+ errno = ENOTSUP;
return FALSE;
}
if (g_b_init_get_security_descriptor_group == 0)
}
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)
{
}
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;
+}
+
\f
/* Return 1 if P is a valid pointer to an object of size SIZE. Return
/* 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;
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
fp += 2;
}
- if (NILP (Vw32_downcase_file_names))
+ if (multibyte || NILP (Vw32_downcase_file_names))
{
while (*fp)
{
} 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.
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
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);
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))
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;
}
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];
static void close_unc_volume (HANDLE);
DIR *
-opendir (char *filename)
+opendir (const char *filename)
{
DIR *dirp;
xfree ((char *) dirp);
}
-struct direct *
+struct dirent *
readdir (DIR *dirp)
{
int downcase = !NILP (Vw32_downcase_file_names);
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
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);
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)
}
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;
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)
{
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)
{
{
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;
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];
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
result = rename (temp, newname);
- if (result < 0)
+ if (result < 0 && force)
{
DWORD w32err = GetLastError ();
return result;
}
+int
+sys_rename (char const *old, char const *new)
+{
+ return sys_rename_replace (old, new, TRUE);
+}
+
int
sys_rmdir (const char * path)
{
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];
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. */
/* 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
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
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
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;
{
/* 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
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
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;
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.
return target;
}
+\f
+/* 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;
+}
+
+\f
/* 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
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)
return NULL;
}
-ssize_t
-careadlinkatcwd (int fd, char const *filename, char *buffer,
- size_t buffer_size)
-{
- (void) fd;
- return readlink (filename, buffer, buffer_size);
-}
-
\f
/* Support for browsing other processes and their attributes. See
process.c for the Lisp bindings. */
{
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)
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 <sys/socket.h> */
+/* 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);
}
if (winsock_lib == NULL)
{
- h_errno = ENETDOWN;
+ errno = ENETDOWN;
return INVALID_SOCKET;
}
}
}
}
+ eassert (fd < MAXDESC);
fd_info[fd].hnd = (HANDLE) s;
/* set our own internal flags */
/* clean up */
_close (fd);
}
+ else
pfn_closesocket (s);
- h_errno = EMFILE;
+ errno = EMFILE;
return -1;
}
{
if (winsock_lib == NULL)
{
- h_errno = ENOTSOCK;
+ errno = ENOTSOCK;
return SOCKET_ERROR;
}
set_errno ();
return rc;
}
- h_errno = ENOTSOCK;
+ errno = ENOTSOCK;
return SOCKET_ERROR;
}
{
if (winsock_lib == NULL)
{
- h_errno = ENOTSOCK;
+ errno = ENOTSOCK;
return SOCKET_ERROR;
}
set_errno ();
return rc;
}
- h_errno = ENOTSOCK;
+ errno = ENOTSOCK;
return SOCKET_ERROR;
}
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;
}
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;
}
if (winsock_lib == NULL)
{
- h_errno = ENETDOWN;
+ errno = ENETDOWN;
return NULL;
}
{
if (winsock_lib == NULL)
{
- h_errno = ENETDOWN;
+ errno = ENETDOWN;
return SOCKET_ERROR;
}
set_errno ();
return rc;
}
- h_errno = ENOTSOCK;
+ errno = ENOTSOCK;
return SOCKET_ERROR;
}
{
if (winsock_lib == NULL)
{
- h_errno = ENETDOWN;
+ errno = ENETDOWN;
return SOCKET_ERROR;
}
set_errno ();
return rc;
}
- h_errno = ENOTSOCK;
+ errno = ENOTSOCK;
return SOCKET_ERROR;
}
{
if (winsock_lib == NULL)
{
- h_errno = ENETDOWN;
+ errno = ENETDOWN;
return SOCKET_ERROR;
}
set_errno ();
return rc;
}
- h_errno = ENOTSOCK;
+ errno = ENOTSOCK;
return SOCKET_ERROR;
}
{
if (winsock_lib == NULL)
{
- h_errno = ENETDOWN;
+ errno = ENETDOWN;
return SOCKET_ERROR;
}
fd_info[s].flags |= FILE_LISTEN;
return rc;
}
- h_errno = ENOTSOCK;
+ errno = ENOTSOCK;
return SOCKET_ERROR;
}
{
if (winsock_lib == NULL)
{
- h_errno = ENETDOWN;
+ errno = ENETDOWN;
return SOCKET_ERROR;
}
set_errno ();
return rc;
}
- h_errno = ENOTSOCK;
+ errno = ENOTSOCK;
return SOCKET_ERROR;
}
{
if (winsock_lib == NULL)
{
- h_errno = ENETDOWN;
+ errno = ENETDOWN;
return -1;
}
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;
}
{
if (winsock_lib == NULL)
{
- h_errno = ENETDOWN;
+ errno = ENETDOWN;
return SOCKET_ERROR;
}
set_errno ();
return rc;
}
- h_errno = ENOTSOCK;
+ errno = ENOTSOCK;
return SOCKET_ERROR;
}
{
if (winsock_lib == NULL)
{
- h_errno = ENETDOWN;
+ errno = ENETDOWN;
return SOCKET_ERROR;
}
set_errno ();
return rc;
}
- h_errno = ENOTSOCK;
+ errno = ENOTSOCK;
return SOCKET_ERROR;
}
{
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);
}
else
{
- h_errno = EINVAL;
+ errno = EINVAL;
return SOCKET_ERROR;
}
}
- h_errno = ENOTSOCK;
+ errno = ENOTSOCK;
return SOCKET_ERROR;
}
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;
}
}
}
{
_close (phandles[0]);
_close (phandles[1]);
+ errno = EMFILE;
rc = -1;
}
else
}
/* 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)
{
/* 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)
pfn_ioctlsocket (SOCK_HANDLE (fd), FIONREAD, &waiting);
if (waiting == 0 && nchars == 0)
{
- h_errno = errno = EWOULDBLOCK;
+ errno = EWOULDBLOCK;
return -1;
}
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
/* "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 */
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