/*
Geoff Voelker (voelker@cs.washington.edu) 7-29-94
*/
+
+#include <mingw_time.h>
#include <stddef.h> /* for offsetof */
#include <stdlib.h>
#include <stdio.h>
#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 */
#undef fopen
#undef link
#undef mkdir
-#undef mktemp
#undef open
#undef rename
#undef rmdir
#undef localtime
#include "lisp.h"
+#include "epaths.h" /* for SHELL */
#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
DWORDLONG ullAvailExtendedVirtual;
} MEMORY_STATUS_EX,*LPMEMORY_STATUS_EX;
+/* These are here so that GDB would know about these data types. This
+ allows to attach GDB to Emacs when a fatal exception is triggered
+ and Windows pops up the "application needs to be closed" dialog.
+ At that point, _gnu_exception_handler, the top-level exception
+ handler installed by the MinGW startup code, is somewhere on the
+ call-stack of the main thread, so going to that call frame and
+ looking at the argument to _gnu_exception_handler, which is a
+ PEXCEPTION_POINTERS pointer, can reveal the exception code
+ (excptr->ExceptionRecord->ExceptionCode) and the address where the
+ exception happened (excptr->ExceptionRecord->ExceptionAddress), as
+ well as some additional information specific to the exception. */
+PEXCEPTION_POINTERS excptr;
+PEXCEPTION_RECORD excprec;
+PCONTEXT ctxrec;
+
#include <lmcons.h>
#include <shlobj.h>
#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>
+
+#include <sys/acl.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. */
+/* 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 recvfrom
#undef sendto
+#include <iphlpapi.h> /* should be after winsock2.h */
+
#include "w32.h"
-#include "ndir.h"
+#include <dirent.h>
#include "w32common.h"
#include "w32heap.h"
#include "w32select.h"
static int restore_privilege (TOKEN_PRIVILEGES *);
static BOOL WINAPI revert_to_self (void);
-extern int sys_access (const char *, int);
+static 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 *);
+ struct timespec *, void *);
+extern int sys_dup (int);
+
\f
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;
+static BOOL g_b_init_get_adapters_info;
/*
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);
+typedef DWORD (WINAPI *GetAdaptersInfo_Proc) (
+ PIP_ADAPTER_INFO pAdapterInfo,
+ PULONG pOutBufLen);
/* ** 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;
+}
+
+static DWORD WINAPI
+get_adapters_info (PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen)
+{
+ static GetAdaptersInfo_Proc s_pfn_Get_Adapters_Info = NULL;
+ HMODULE hm_iphlpapi = NULL;
+
+ if (is_windows_9x () == TRUE)
+ return ERROR_NOT_SUPPORTED;
+
+ if (g_b_init_get_adapters_info == 0)
+ {
+ g_b_init_get_adapters_info = 1;
+ hm_iphlpapi = LoadLibrary ("Iphlpapi.dll");
+ if (hm_iphlpapi)
+ s_pfn_Get_Adapters_Info = (GetAdaptersInfo_Proc)
+ GetProcAddress (hm_iphlpapi, "GetAdaptersInfo");
+ }
+ if (s_pfn_Get_Adapters_Info == NULL)
+ return ERROR_NOT_SUPPORTED;
+ return s_pfn_Get_Adapters_Info (pAdapterInfo, pOutBufLen);
+}
+
\f
/* Return 1 if P is a valid pointer to an object of size SIZE. Return
return -1;
}
-static char startup_dir[MAXPATHLEN];
+\f
+
+/* Converting file names from UTF-8 to either UTF-16 or the ANSI
+ codepage defined by file-name-coding-system. */
+
+/* Current codepage for encoding file names. */
+static int file_name_codepage;
+
+/* Produce a Windows ANSI codepage suitable for encoding file names.
+ Return the information about that codepage in CP_INFO. */
+static int
+codepage_for_filenames (CPINFO *cp_info)
+{
+ /* A simple cache to avoid calling GetCPInfo every time we need to
+ encode/decode a file name. The file-name encoding is not
+ supposed to be changed too frequently, if ever. */
+ static Lisp_Object last_file_name_encoding;
+ static CPINFO cp;
+ Lisp_Object current_encoding;
+
+ current_encoding = Vfile_name_coding_system;
+ if (NILP (current_encoding))
+ current_encoding = Vdefault_file_name_coding_system;
+
+ if (!EQ (last_file_name_encoding, current_encoding))
+ {
+ /* Default to the current ANSI codepage. */
+ file_name_codepage = w32_ansi_code_page;
+
+ if (NILP (current_encoding))
+ {
+ char *cpname = SDATA (SYMBOL_NAME (current_encoding));
+ char *cp = NULL, *end;
+ int cpnum;
+
+ if (strncmp (cpname, "cp", 2) == 0)
+ cp = cpname + 2;
+ else if (strncmp (cpname, "windows-", 8) == 0)
+ cp = cpname + 8;
+
+ if (cp)
+ {
+ end = cp;
+ cpnum = strtol (cp, &end, 10);
+ if (cpnum && *end == '\0' && end - cp >= 2)
+ file_name_codepage = cpnum;
+ }
+ }
+
+ if (!file_name_codepage)
+ file_name_codepage = CP_ACP; /* CP_ACP = 0, but let's not assume that */
+
+ if (!GetCPInfo (file_name_codepage, &cp))
+ {
+ file_name_codepage = CP_ACP;
+ if (!GetCPInfo (file_name_codepage, &cp))
+ emacs_abort ();
+ }
+ }
+ if (cp_info)
+ *cp_info = cp;
+
+ return file_name_codepage;
+}
+
+static int
+filename_to_utf16 (const char *fn_in, wchar_t *fn_out)
+{
+ int result = MultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, fn_in, -1,
+ fn_out, MAX_PATH);
+
+ if (!result)
+ {
+ DWORD err = GetLastError ();
+
+ switch (err)
+ {
+ case ERROR_INVALID_FLAGS:
+ case ERROR_INVALID_PARAMETER:
+ errno = EINVAL;
+ break;
+ case ERROR_INSUFFICIENT_BUFFER:
+ case ERROR_NO_UNICODE_TRANSLATION:
+ default:
+ errno = ENOENT;
+ break;
+ }
+ return -1;
+ }
+ return 0;
+}
+
+static int
+filename_from_utf16 (const wchar_t *fn_in, char *fn_out)
+{
+ int result = WideCharToMultiByte (CP_UTF8, 0, fn_in, -1,
+ fn_out, MAX_UTF8_PATH, NULL, NULL);
+
+ if (!result)
+ {
+ DWORD err = GetLastError ();
+
+ switch (err)
+ {
+ case ERROR_INVALID_FLAGS:
+ case ERROR_INVALID_PARAMETER:
+ errno = EINVAL;
+ break;
+ case ERROR_INSUFFICIENT_BUFFER:
+ case ERROR_NO_UNICODE_TRANSLATION:
+ default:
+ errno = ENOENT;
+ break;
+ }
+ return -1;
+ }
+ return 0;
+}
+
+static int
+filename_to_ansi (const char *fn_in, char *fn_out)
+{
+ wchar_t fn_utf16[MAX_PATH];
+
+ if (filename_to_utf16 (fn_in, fn_utf16) == 0)
+ {
+ int result;
+ int codepage = codepage_for_filenames (NULL);
+
+ result = WideCharToMultiByte (codepage, 0, fn_utf16, -1,
+ fn_out, MAX_PATH, NULL, NULL);
+ if (!result)
+ {
+ DWORD err = GetLastError ();
+
+ switch (err)
+ {
+ case ERROR_INVALID_FLAGS:
+ case ERROR_INVALID_PARAMETER:
+ errno = EINVAL;
+ break;
+ case ERROR_INSUFFICIENT_BUFFER:
+ case ERROR_NO_UNICODE_TRANSLATION:
+ default:
+ errno = ENOENT;
+ break;
+ }
+ return -1;
+ }
+ return 0;
+ }
+ return -1;
+}
+
+int
+filename_from_ansi (const char *fn_in, char *fn_out)
+{
+ wchar_t fn_utf16[MAX_PATH];
+ int codepage = codepage_for_filenames (NULL);
+ int result = MultiByteToWideChar (codepage, MB_ERR_INVALID_CHARS, fn_in, -1,
+ fn_utf16, MAX_PATH);
+
+ if (!result)
+ {
+ DWORD err = GetLastError ();
+
+ switch (err)
+ {
+ case ERROR_INVALID_FLAGS:
+ case ERROR_INVALID_PARAMETER:
+ errno = EINVAL;
+ break;
+ case ERROR_INSUFFICIENT_BUFFER:
+ case ERROR_NO_UNICODE_TRANSLATION:
+ default:
+ errno = ENOENT;
+ break;
+ }
+ return -1;
+ }
+ return filename_from_utf16 (fn_utf16, fn_out);
+}
+
+\f
+
+/* The directory where we started, in UTF-8. */
+static char startup_dir[MAX_UTF8_PATH];
/* 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;
static char dflt_passwd_name[PASSWD_FIELD_SIZE];
static char dflt_passwd_passwd[PASSWD_FIELD_SIZE];
static char dflt_passwd_gecos[PASSWD_FIELD_SIZE];
-static char dflt_passwd_dir[PASSWD_FIELD_SIZE];
-static char dflt_passwd_shell[PASSWD_FIELD_SIZE];
+static char dflt_passwd_dir[MAX_UTF8_PATH];
+static char dflt_passwd_shell[MAX_UTF8_PATH];
static struct passwd dflt_passwd =
{
}
dflt_group.gr_gid = dflt_passwd.pw_gid;
- /* Ensure HOME and SHELL are defined. */
- if (getenv ("HOME") == NULL)
- emacs_abort ();
- if (getenv ("SHELL") == NULL)
- emacs_abort ();
-
/* Set dir and shell from environment variables. */
- strcpy (dflt_passwd.pw_dir, getenv ("HOME"));
- strcpy (dflt_passwd.pw_shell, getenv ("SHELL"));
+ if (w32_unicode_filenames)
+ {
+ wchar_t *home = _wgetenv (L"HOME");
+ wchar_t *shell = _wgetenv (L"SHELL");
+
+ /* Ensure HOME and SHELL are defined. */
+ if (home == NULL)
+ emacs_abort ();
+ if (shell == NULL)
+ emacs_abort ();
+ filename_from_utf16 (home, dflt_passwd.pw_dir);
+ filename_from_utf16 (shell, dflt_passwd.pw_shell);
+ }
+ else
+ {
+ char *home = getenv ("HOME");
+ char *shell = getenv ("SHELL");
+
+ if (home == NULL)
+ emacs_abort ();
+ if (shell == NULL)
+ emacs_abort ();
+ filename_from_ansi (home, dflt_passwd.pw_dir);
+ filename_from_ansi (shell, dflt_passwd.pw_shell);
+ }
xfree (buf);
if (token)
srand (seed);
}
-/* Current codepage for encoding file names. */
-static int file_name_codepage;
-
/* Return the maximum length in bytes of a multibyte character
sequence encoded in the current ANSI codepage. This is required to
correctly walk the encoded file names one character at a time. */
static int
max_filename_mbslen (void)
{
- /* A simple cache to avoid calling GetCPInfo every time we need to
- normalize a file name. The file-name encoding is not supposed to
- be changed too frequently, if ever. */
- static Lisp_Object last_file_name_encoding;
- static int last_max_mbslen;
- Lisp_Object current_encoding;
-
- current_encoding = Vfile_name_coding_system;
- if (NILP (current_encoding))
- current_encoding = Vdefault_file_name_coding_system;
-
- if (!EQ (last_file_name_encoding, current_encoding))
- {
- CPINFO cp_info;
+ CPINFO cp_info;
- last_file_name_encoding = current_encoding;
- /* Default to the current ANSI codepage. */
- file_name_codepage = w32_ansi_code_page;
- if (!NILP (current_encoding))
- {
- char *cpname = SDATA (SYMBOL_NAME (current_encoding));
- char *cp = NULL, *end;
- int cpnum;
-
- if (strncmp (cpname, "cp", 2) == 0)
- cp = cpname + 2;
- else if (strncmp (cpname, "windows-", 8) == 0)
- cp = cpname + 8;
-
- if (cp)
- {
- end = cp;
- cpnum = strtol (cp, &end, 10);
- if (cpnum && *end == '\0' && end - cp >= 2)
- file_name_codepage = cpnum;
- }
- }
-
- if (!file_name_codepage)
- file_name_codepage = CP_ACP; /* CP_ACP = 0, but let's not assume that */
-
- if (!GetCPInfo (file_name_codepage, &cp_info))
- {
- file_name_codepage = CP_ACP;
- if (!GetCPInfo (file_name_codepage, &cp_info))
- emacs_abort ();
- }
- last_max_mbslen = cp_info.MaxCharSize;
- }
-
- return last_max_mbslen;
+ codepage_for_filenames (&cp_info);
+ return cp_info.MaxCharSize;
}
-/* Normalize filename by converting all path separators to
- the specified separator. Also conditionally convert upper
- case path name components to lower case. */
+/* Normalize filename by converting in-place all of its path
+ separators to the separator specified by PATH_SEP. */
static void
normalize_filename (register char *fp, char path_sep)
{
- char sep;
- char *elem, *p2;
- int dbcs_p = max_filename_mbslen () > 1;
+ char *p2;
/* 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
functions that are case-sensitive. Even case-preserving filesystems
do not distinguish case in drive letters. */
- if (dbcs_p)
- p2 = CharNextExA (file_name_codepage, fp, 0);
- else
- p2 = fp + 1;
+ p2 = fp + 1;
if (*p2 == ':' && *fp >= 'A' && *fp <= 'Z')
{
fp += 2;
}
- if (NILP (Vw32_downcase_file_names))
+ while (*fp)
{
- while (*fp)
- {
- if (*fp == '/' || *fp == '\\')
- *fp = path_sep;
- if (!dbcs_p)
- fp++;
- else
- fp = CharNextExA (file_name_codepage, fp, 0);
- }
- return;
+ if (*fp == '/' || *fp == '\\')
+ *fp = path_sep;
+ fp++;
}
-
- sep = path_sep; /* convert to this path separator */
- elem = fp; /* start of current path element */
-
- do {
- if (*fp >= 'a' && *fp <= 'z')
- elem = 0; /* don't convert this element */
-
- if (*fp == 0 || *fp == ':')
- {
- sep = *fp; /* restore current separator (or 0) */
- *fp = '/'; /* after conversion of this element */
- }
-
- if (*fp == '/' || *fp == '\\')
- {
- if (elem && elem != fp)
- {
- *fp = 0; /* temporary end of string */
- _mbslwr (elem); /* while we convert to lower case */
- }
- *fp = sep; /* convert (or restore) path separator */
- elem = fp + 1; /* next element starts after separator */
- sep = path_sep;
- }
- if (*fp)
- {
- if (!dbcs_p)
- fp++;
- else
- fp = CharNextExA (file_name_codepage, fp, 0);
- }
- } while (*fp);
}
/* Destructively turn backslashes into slashes. */
/* Parse the root part of file name, if present. Return length and
optionally store pointer to char after root. */
static int
-parse_root (char * name, char ** pPath)
+parse_root (const char * name, const char ** pPath)
{
- char * start = name;
+ const char * start = name;
if (name == NULL)
return 0;
else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
{
int slashes = 2;
- int dbcs_p = max_filename_mbslen () > 1;
name += 2;
do
{
if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
break;
- if (dbcs_p)
- name = CharNextExA (file_name_codepage, name, 0);
- else
- name++;
+ name++;
}
while ( *name );
if (IS_DIRECTORY_SEP (name[0]))
static int
get_long_basename (char * name, char * buf, int size)
{
- WIN32_FIND_DATA find_data;
HANDLE dir_handle;
+ char fname_utf8[MAX_UTF8_PATH];
int len = 0;
+ int cstatus;
- /* must be valid filename, no wild cards or other invalid characters */
- if (_mbspbrk (name, "*?|<>\""))
+ /* Must be valid filename, no wild cards or other invalid characters. */
+ if (strpbrk (name, "*?|<>\""))
return 0;
- dir_handle = FindFirstFile (name, &find_data);
- if (dir_handle != INVALID_HANDLE_VALUE)
+ if (w32_unicode_filenames)
{
- if ((len = strlen (find_data.cFileName)) < size)
- memcpy (buf, find_data.cFileName, len + 1);
- else
- len = 0;
- FindClose (dir_handle);
+ wchar_t fname_utf16[MAX_PATH];
+ WIN32_FIND_DATAW find_data_wide;
+
+ filename_to_utf16 (name, fname_utf16);
+ dir_handle = FindFirstFileW (fname_utf16, &find_data_wide);
+ if (dir_handle != INVALID_HANDLE_VALUE)
+ cstatus = filename_from_utf16 (find_data_wide.cFileName, fname_utf8);
+ }
+ else
+ {
+ char fname_ansi[MAX_PATH];
+ WIN32_FIND_DATAA find_data_ansi;
+
+ filename_to_ansi (name, fname_ansi);
+ dir_handle = FindFirstFileA (fname_ansi, &find_data_ansi);
+ if (dir_handle != INVALID_HANDLE_VALUE)
+ cstatus = filename_from_ansi (find_data_ansi.cFileName, fname_utf8);
}
+
+ if (cstatus == 0 && (len = strlen (fname_utf8)) < size)
+ memcpy (buf, fname_utf8, len + 1);
+ else
+ len = 0;
+
+ if (dir_handle != INVALID_HANDLE_VALUE)
+ FindClose (dir_handle);
+
return len;
}
{
char * o = buf;
char * p;
- char * q;
- char full[ MAX_PATH ];
+ const char * q;
+ char full[ MAX_UTF8_PATH ];
int len;
len = strlen (name);
- if (len >= MAX_PATH)
+ if (len >= MAX_UTF8_PATH)
return FALSE;
/* Use local copy for destructive modification. */
unixtodos_filename (full);
/* Copy root part verbatim. */
- len = parse_root (full, &p);
+ len = parse_root (full, (const char **)&p);
memcpy (o, full, len);
o += len;
*o = '\0';
while (p != NULL && *p)
{
q = p;
- p = _mbschr (q, '\\');
+ p = strchr (q, '\\');
if (p) *p = '\0';
len = get_long_basename (full, o, size);
if (len > 0)
return TRUE;
}
+unsigned int
+w32_get_short_filename (char * name, char * buf, int size)
+{
+ if (w32_unicode_filenames)
+ {
+ wchar_t name_utf16[MAX_PATH], short_name[MAX_PATH];
+ unsigned int retval;
+
+ filename_to_utf16 (name, name_utf16);
+ retval = GetShortPathNameW (name_utf16, short_name, size);
+ if (retval && retval < size)
+ filename_from_utf16 (short_name, buf);
+ return retval;
+ }
+ else
+ {
+ char name_ansi[MAX_PATH];
+
+ filename_to_ansi (name, name_ansi);
+ return GetShortPathNameA (name_ansi, buf, size);
+ }
+}
+
static int
is_unc_volume (const char *filename)
{
if (!IS_DIRECTORY_SEP (ptr[0]) || !IS_DIRECTORY_SEP (ptr[1]) || !ptr[2])
return 0;
- if (_mbspbrk (ptr + 2, "*?|<>\"\\/"))
+ if (strpbrk (ptr + 2, "*?|<>\"\\/"))
return 0;
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
return (NULL);
}
-char *get_emacs_configuration (void);
-
void
init_environment (char ** argv)
{
const int imax = sizeof (tempdirs) / sizeof (tempdirs[0]);
+ /* Implementation note: This function explicitly works with ANSI
+ file names, not with UTF-8 encoded file names. This is because
+ this function pushes variables into the Emacs's environment, and
+ the environment variables are always assumed to be in the
+ locale-specific encoding. Do NOT call any functions that accept
+ UTF-8 file names from this function! */
+
/* Make sure they have a usable $TMPDIR. Many Emacs functions use
temporary files and assume "/tmp" if $TMPDIR is unset, which
will break on DOS/Windows. Refuse to work if we cannot find
The only way to be really sure is to actually create a file and
see if it succeeds. But I think that's too much to ask. */
- /* MSVCRT's _access crashes with D_OK. */
+ /* MSVCRT's _access crashes with D_OK, so we use our replacement. */
if (tmp && sys_access (tmp, D_OK) == 0)
{
char * var = alloca (strlen (tmp) + 8);
{"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},
/* 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 (!check_existing ("C:/.emacs"))
+ if (sys_access ("C:/.emacs", F_OK) != 0)
{
HRESULT profile_result;
/* Dynamically load ShGetFolderPath, as it won't exist on versions
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))
_snprintf (buf, sizeof (buf)-1, "emacs_dir=%s", modname);
_putenv (strdup (buf));
- }
- /* Handle running emacs from the build directory: src/oo-spd/i386/ */
-
- /* FIXME: should use substring of get_emacs_configuration ().
- But I don't think the Windows build supports alpha, mips etc
- anymore, so have taken the easy option for now. */
- else if (p && (xstrcasecmp (p, "\\i386") == 0
- || xstrcasecmp (p, "\\AMD64") == 0))
- {
- *p = 0;
- p = _mbsrchr (modname, '\\');
- if (p != NULL)
+ /* 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)
{
- *p = 0;
- p = _mbsrchr (modname, '\\');
- if (p && xstrcasecmp (p, "\\src") == 0)
- {
- char buf[SET_ENV_BUF_SIZE];
-
- *p = 0;
- for (p = modname; *p; p = CharNext (p))
- if (*p == '\\') *p = '/';
-
- _snprintf (buf, sizeof (buf)-1, "emacs_dir=%s", modname);
- _putenv (strdup (buf));
- }
+ _snprintf (buf, sizeof (buf) - 1,
+ "SHELL=%s/nt/cmdproxy.exe", modname);
+ _putenv (strdup (buf));
}
}
}
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 (sys_access (bufc, F_OK) == 0)
+ {
+ 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"),
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 ();
+ if (w32_unicode_filenames)
+ {
+ wchar_t wstartup_dir[MAX_PATH];
+
+ if (!GetCurrentDirectoryW (MAX_PATH, wstartup_dir))
+ emacs_abort ();
+ filename_from_utf16 (wstartup_dir, startup_dir);
+ }
+ else
+ {
+ char astartup_dir[MAX_PATH];
+
+ if (!GetCurrentDirectoryA (MAX_PATH, astartup_dir))
+ emacs_abort ();
+ filename_from_ansi (astartup_dir, startup_dir);
+ }
{
static char modname[MAX_PATH];
char *
emacs_root_dir (void)
{
- static char root_dir[FILENAME_MAX];
+ static char root_dir[MAX_UTF8_PATH];
const char *p;
p = getenv ("emacs_dir");
if (p == NULL)
emacs_abort ();
- strcpy (root_dir, p);
+ filename_from_ansi (p, root_dir);
root_dir[parse_root (root_dir, NULL)] = '\0';
dostounix_filename (root_dir);
return root_dir;
}
-/* We don't have scripts to automatically determine the system configuration
- for Emacs before it's compiled, and we don't want to have to make the
- user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
- routine. */
-
-char *
-get_emacs_configuration (void)
-{
- char *arch, *oem, *os;
- int build_num;
- static char configuration_buffer[32];
-
- /* Determine the processor type. */
- switch (get_processor_type ())
- {
-
-#ifdef PROCESSOR_INTEL_386
- case PROCESSOR_INTEL_386:
- case PROCESSOR_INTEL_486:
- case PROCESSOR_INTEL_PENTIUM:
-#ifdef _WIN64
- arch = "amd64";
-#else
- arch = "i386";
-#endif
- break;
-#endif
-#ifdef PROCESSOR_AMD_X8664
- case PROCESSOR_AMD_X8664:
- arch = "amd64";
- break;
-#endif
-
-#ifdef PROCESSOR_MIPS_R2000
- case PROCESSOR_MIPS_R2000:
- case PROCESSOR_MIPS_R3000:
- case PROCESSOR_MIPS_R4000:
- arch = "mips";
- break;
-#endif
-
-#ifdef PROCESSOR_ALPHA_21064
- case PROCESSOR_ALPHA_21064:
- arch = "alpha";
- break;
-#endif
-
- default:
- arch = "unknown";
- break;
- }
-
- /* Use the OEM field to reflect the compiler/library combination. */
-#ifdef _MSC_VER
-#define COMPILER_NAME "msvc"
-#else
-#ifdef __GNUC__
-#define COMPILER_NAME "mingw"
-#else
-#define COMPILER_NAME "unknown"
-#endif
-#endif
- oem = COMPILER_NAME;
-
- switch (osinfo_cache.dwPlatformId) {
- case VER_PLATFORM_WIN32_NT:
- os = "nt";
- build_num = osinfo_cache.dwBuildNumber;
- break;
- case VER_PLATFORM_WIN32_WINDOWS:
- if (osinfo_cache.dwMinorVersion == 0) {
- os = "windows95";
- } else {
- os = "windows98";
- }
- build_num = LOWORD (osinfo_cache.dwBuildNumber);
- break;
- case VER_PLATFORM_WIN32s:
- /* Not supported, should not happen. */
- os = "windows32s";
- build_num = LOWORD (osinfo_cache.dwBuildNumber);
- break;
- default:
- os = "unknown";
- build_num = 0;
- break;
- }
-
- if (osinfo_cache.dwPlatformId == VER_PLATFORM_WIN32_NT) {
- sprintf (configuration_buffer, "%s-%s-%s%d.%d.%d", arch, oem, os,
- get_w32_major_version (), get_w32_minor_version (), build_num);
- } else {
- sprintf (configuration_buffer, "%s-%s-%s.%d", arch, oem, os, build_num);
- }
-
- return configuration_buffer;
-}
-
-char *
-get_emacs_configuration_options (void)
-{
- static char *options_buffer;
- char cv[32]; /* Enough for COMPILER_VERSION. */
- char *options[] = {
- cv, /* To be filled later. */
-#ifdef EMACSDEBUG
- " --no-opt",
-#endif
-#ifdef ENABLE_CHECKING
- " --enable-checking",
-#endif
- /* configure.bat already sets USER_CFLAGS and USER_LDFLAGS
- with a starting space to save work here. */
-#ifdef USER_CFLAGS
- " --cflags", USER_CFLAGS,
-#endif
-#ifdef USER_LDFLAGS
- " --ldflags", USER_LDFLAGS,
-#endif
- NULL
- };
- size_t size = 0;
- int i;
-
-/* Work out the effective configure options for this build. */
-#ifdef _MSC_VER
-#define COMPILER_VERSION "--with-msvc (%d.%02d)", _MSC_VER / 100, _MSC_VER % 100
-#else
-#ifdef __GNUC__
-#define COMPILER_VERSION "--with-gcc (%d.%d)", __GNUC__, __GNUC_MINOR__
-#else
-#define COMPILER_VERSION ""
-#endif
-#endif
-
- if (_snprintf (cv, sizeof (cv) - 1, COMPILER_VERSION) < 0)
- return "Error: not enough space for compiler version";
- cv[sizeof (cv) - 1] = '\0';
-
- for (i = 0; options[i]; i++)
- size += strlen (options[i]);
-
- options_buffer = xmalloc (size + 1);
- options_buffer[0] = '\0';
-
- for (i = 0; options[i]; i++)
- strcat (options_buffer, options[i]);
-
- return options_buffer;
-}
-
-
#include <sys/timeb.h>
/* 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);
tz->tz_minuteswest = tb.timezone; /* minutes west of Greenwich */
tz->tz_dsttime = tb.dstflag; /* type of dst correction */
}
+ return 0;
}
/* Emulate fdutimens. */
int
fdutimens (int fd, char const *file, struct timespec const timespec[2])
{
- struct _utimbuf ut;
-
if (!timespec)
{
errno = ENOSYS;
errno = EBADF;
return -1;
}
- ut.actime = timespec[0].tv_sec;
- ut.modtime = timespec[1].tv_sec;
+ /* _futime's prototype defines 2nd arg as having the type 'struct
+ _utimbuf', while utime needs to accept 'struct utimbuf' for
+ compatibility with Posix. So we need to use 2 different (but
+ equivalent) types to avoid compiler warnings, sigh. */
if (fd >= 0)
- return _futime (fd, &ut);
+ {
+ struct _utimbuf _ut;
+
+ _ut.actime = timespec[0].tv_sec;
+ _ut.modtime = timespec[1].tv_sec;
+ return _futime (fd, &_ut);
+ }
else
- return _utime (file, &ut);
+ {
+ struct utimbuf ut;
+
+ ut.actime = timespec[0].tv_sec;
+ ut.modtime = timespec[1].tv_sec;
+ /* Call 'utime', which is implemented below, not the MS library
+ function, which fails on directories. */
+ return utime (file, &ut);
+ }
}
add_volume_info (char * root_dir, volume_info_data * info)
{
info->root_dir = xstrdup (root_dir);
+ unixtodos_filename (info->root_dir);
info->next = volume_cache;
volume_cache = info;
}
GetCachedVolumeInformation (char * root_dir)
{
volume_info_data * info;
- char default_root[ MAX_PATH ];
+ char default_root[ MAX_UTF8_PATH ];
+ char name[MAX_PATH+1];
+ char type[MAX_PATH+1];
/* NULL for root_dir means use root from current directory. */
if (root_dir == NULL)
{
- if (GetCurrentDirectory (MAX_PATH, default_root) == 0)
- return NULL;
- parse_root (default_root, &root_dir);
+ if (w32_unicode_filenames)
+ {
+ wchar_t curdirw[MAX_PATH];
+
+ if (GetCurrentDirectoryW (MAX_PATH, curdirw) == 0)
+ return NULL;
+ filename_from_utf16 (curdirw, default_root);
+ }
+ else
+ {
+ char curdira[MAX_PATH];
+
+ if (GetCurrentDirectoryA (MAX_PATH, curdira) == 0)
+ return NULL;
+ filename_from_ansi (curdira, default_root);
+ }
+ parse_root (default_root, (const char **)&root_dir);
*root_dir = 0;
root_dir = default_root;
}
if (info == NULL || ! VOLINFO_STILL_VALID (root_dir, info))
{
- char name[ 256 ];
DWORD serialnum;
DWORD maxcomp;
DWORD flags;
- char type[ 256 ];
/* Info is not cached, or is stale. */
- if (!GetVolumeInformation (root_dir,
- name, sizeof (name),
- &serialnum,
- &maxcomp,
- &flags,
- type, sizeof (type)))
- return NULL;
+ if (w32_unicode_filenames)
+ {
+ wchar_t root_w[MAX_PATH];
+ wchar_t name_w[MAX_PATH+1];
+ wchar_t type_w[MAX_PATH+1];
+
+ filename_to_utf16 (root_dir, root_w);
+ if (!GetVolumeInformationW (root_w,
+ name_w, sizeof (name_w),
+ &serialnum,
+ &maxcomp,
+ &flags,
+ type_w, sizeof (type_w)))
+ return NULL;
+ /* Hmm... not really 100% correct, as these 2 are not file
+ names... */
+ filename_from_utf16 (name_w, name);
+ filename_from_utf16 (type_w, type);
+ }
+ else
+ {
+ char root_a[MAX_PATH];
+ char name_a[MAX_PATH+1];
+ char type_a[MAX_PATH+1];
+
+ filename_to_ansi (root_dir, root_a);
+ if (!GetVolumeInformationA (root_a,
+ name_a, sizeof (name_a),
+ &serialnum,
+ &maxcomp,
+ &flags,
+ type_a, sizeof (type_a)))
+ return NULL;
+ filename_from_ansi (name_a, name);
+ filename_from_ansi (type_a, type);
+ }
/* Cache the volume information for future use, overwriting existing
entry if present. */
}
info->name = xstrdup (name);
+ unixtodos_filename (info->name);
info->serialnum = serialnum;
info->maxcomp = maxcomp;
info->flags = flags;
static int
get_volume_info (const char * name, const char ** pPath)
{
- char temp[MAX_PATH];
+ char temp[MAX_UTF8_PATH];
char *rootname = NULL; /* default to current volume */
volume_info_data * info;
+ int root_len = parse_root (name, pPath);
if (name == NULL)
return FALSE;
- /* Find the root name of the volume if given. */
- if (isalpha (name[0]) && name[1] == ':')
- {
- rootname = temp;
- temp[0] = *name++;
- temp[1] = *name++;
- temp[2] = '\\';
- temp[3] = 0;
- }
- else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
+ /* Copy the root name of the volume, if given. */
+ if (root_len)
{
- char *str = temp;
- int slashes = 4;
- int dbcs_p = max_filename_mbslen () > 1;
-
+ strncpy (temp, name, root_len);
+ temp[root_len] = '\0';
+ unixtodos_filename (temp);
rootname = temp;
- do
- {
- if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
- break;
- if (!dbcs_p)
- *str++ = *name++;
- else
- {
- const char *p = name;
-
- name = CharNextExA (file_name_codepage, name, 0);
- memcpy (str, p, name - p);
- str += name - p;
- }
- }
- while ( *name );
-
- *str++ = '\\';
- *str = 0;
}
- if (pPath)
- *pPath = name;
-
info = GetCachedVolumeInformation (rootname);
if (info != NULL)
{
return FALSE;
}
-/* Map filename to a valid 8.3 name if necessary.
- The result is a pointer to a static buffer, so CAVEAT EMPTOR! */
+/* Convert all slashes in a filename to backslashes, and map filename
+ to a valid 8.3 name if necessary. The result is a pointer to a
+ static buffer, so CAVEAT EMPTOR! */
const char *
map_w32_filename (const char * name, const char ** pPath)
{
- static char shortname[MAX_PATH];
+ static char shortname[MAX_UTF8_PATH];
char * str = shortname;
char c;
char * path;
const char * save_name = name;
- if (strlen (name) >= MAX_PATH)
+ if (strlen (name) >= sizeof (shortname))
{
/* Return a filename which will cause callers to fail. */
strcpy (shortname, "?");
str[-1] = c; /* replace last character of part */
/* FALLTHRU */
default:
- if ( left )
+ if ( left && 'A' <= c && c <= 'Z' )
{
*str++ = tolower (c); /* map to lower case (looks nicer) */
left--;
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;
+ }
+ if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0)
+ {
+ errno = EACCES;
+ return -1;
+ }
+ if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
+ {
+ errno = EACCES;
+ return -1;
+ }
+ return 0;
+}
+
+/* A version of 'access' to be used locally with file names in
+ locale-specific encoding. Does not resolve symlinks and does not
+ support file names on FAT12 and FAT16 volumes, but that's OK, since
+ we only invoke this function for files inside the Emacs source or
+ installation tree, on directories (so any symlinks should have the
+ directory bit set), and on short file names such as "C:/.emacs". */
+static int
+sys_access (const char *fname, int mode)
+{
+ char fname_copy[MAX_PATH], *p;
+ DWORD attributes;
+
+ strcpy (fname_copy, fname);
+ /* Do the equivalent of unixtodos_filename. */
+ for (p = fname_copy; *p; p = CharNext (p))
+ if (*p == '/')
+ *p = '\\';
+
+ if ((attributes = GetFileAttributesA (fname_copy)) == -1)
+ {
+ DWORD w32err = GetLastError ();
+
+ switch (w32err)
+ {
+ case ERROR_INVALID_NAME:
+ case ERROR_BAD_PATHNAME:
+ case ERROR_FILE_NOT_FOUND:
+ case ERROR_BAD_NETPATH:
+ errno = ENOENT;
+ break;
+ default:
+ errno = EACCES;
+ break;
+ }
+ return -1;
+ }
+ if ((mode & X_OK) != 0
+ && !(is_exec (fname_copy)
+ || (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 _chdir (map_w32_filename (path, NULL));
+ /* FIXME: Temporary. Also, figure out what to do with
+ map_w32_filename, as the original code did this:
+ _chdir(map_w32_filename (path, NULL)). */
+ if (w32_unicode_filenames)
+ {
+ wchar_t newdir[MAXPATHLEN];
+
+ if (filename_to_utf16 (path, newdir) == 0)
+ return _wchdir (newdir);
+ return -1;
+ }
+ else
+ {
+ char newdir[MAXPATHLEN];
+
+ if (filename_to_ansi (path, newdir) == 0)
+ return _chdir (path);
+ return -1;
+ }
}
int
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)
{
return _mkdir (map_w32_filename (path, NULL));
}
-/* Because of long name mapping issues, we need to implement this
- ourselves. Also, MSVC's _mktemp returns NULL when it can't generate
- a unique name, instead of setting the input template to an empty
- string.
+int
+sys_open (const char * path, int oflag, int mode)
+{
+ const char* mpath = map_w32_filename (path, NULL);
+ 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);
+
+ return res;
+}
+
+/* Implementation of mkostemp for MS-Windows, to avoid race conditions
+ when using mktemp.
- Standard algorithm seems to be use pid or tid with a letter on the
- front (in place of the 6 X's) and cycle through the letters to find a
- unique name. We extend that to allow any reasonable character as the
- first of the 6 X's. */
-char *
-sys_mktemp (char * template)
+ Standard algorithm for generating a temporary file name seems to be
+ use pid or tid with a letter on the front (in place of the 6 X's)
+ and cycle through the letters to find a unique name. We extend
+ that to allow any reasonable character as the first of the 6 X's,
+ so that the number of simultaneously used temporary files will be
+ greater. */
+
+int
+mkostemp (char * template, int flags)
{
char * p;
- int i;
+ int i, fd = -1;
unsigned uid = GetCurrentThreadId ();
+ int save_errno = errno;
static char first_char[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
+ errno = EINVAL;
if (template == NULL)
- return NULL;
+ return -1;
+
p = template + strlen (template);
i = 5;
/* replace up to the last 5 X's with uid in decimal */
i = 0;
do
{
- int save_errno = errno;
p[0] = first_char[i];
- if (sys_access (template, 0) < 0)
+ if ((fd = sys_open (template,
+ flags | _O_CREAT | _O_EXCL | _O_RDWR,
+ S_IRUSR | S_IWUSR)) >= 0
+ || errno != EEXIST)
{
- errno = save_errno;
- return template;
+ if (fd >= 0)
+ errno = save_errno;
+ return fd;
}
}
while (++i < sizeof (first_char));
}
- /* Template is badly formed or else we can't generate a unique name,
- so return empty string */
- template[0] = 0;
- return template;
+ /* Template is badly formed or else we can't generate a unique name. */
+ return -1;
}
int
-sys_open (const char * path, int oflag, int mode)
+fchmod (int fd, mode_t 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);
- if (res < 0)
- res = _open (mpath, oflag | _O_NOINHERIT, mode);
- if (res >= 0 && res < MAXDESC)
- fd_info[res].flags = 0;
-
- return res;
+ return 0;
}
int
-sys_rename (const char * oldname, const char * newname)
+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)
{
pft->dwLowDateTime = tmp.LowPart;
}
-#if 0
-/* No reason to keep this; faking inode values either by hashing or even
- using the file index from GetInformationByHandle, is not perfect and
- so by default Emacs doesn't use the inode values on Windows.
- Instead, we now determine file-truename correctly (except for
- possible drive aliasing etc). */
-
-/* Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
-static unsigned
-hashval (const unsigned char * str)
-{
- unsigned h = 0;
- while (*str)
- {
- h = (h << 4) + *str++;
- h ^= (h >> 28);
- }
- return h;
-}
-
-/* Return the hash value of the canonical pathname, excluding the
- drive/UNC header, to get a hopefully unique inode number. */
-static DWORD
-generate_inode_val (const char * name)
-{
- char fullname[ MAX_PATH ];
- char * p;
- unsigned hash;
-
- /* Get the truly canonical filename, if it exists. (Note: this
- doesn't resolve aliasing due to subst commands, or recognize hard
- links. */
- if (!w32_get_long_filename ((char *)name, fullname, MAX_PATH))
- emacs_abort ();
-
- parse_root (fullname, &p);
- /* Normal W32 filesystems are still case insensitive. */
- _strlwr (p);
- return hashval (p);
-}
-
-#endif
-
static PSECURITY_DESCRIPTOR
get_file_security_desc_by_handle (HANDLE h)
{
/* Caching SID and account values for faster lokup. */
-#ifdef __GNUC__
-# define FLEXIBLE_ARRAY_MEMBER
-#else
-# define FLEXIBLE_ARRAY_MEMBER 1
-#endif
-
struct w32_id {
unsigned rid;
struct w32_id *next;
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;
return 0;
}
+/* A version of 'utime' which handles directories as well as
+ files. */
+
int
utime (const char *name, struct utimbuf *times)
{
times = &deftime;
}
- /* Need write access to set times. */
- 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 (w32_unicode_filenames)
+ {
+ wchar_t name_utf16[MAX_PATH];
+
+ if (filename_to_utf16 (name, name_utf16) != 0)
+ return -1; /* errno set by filename_to_utf16 */
+
+ /* Need write access to set times. */
+ fh = CreateFileW (name_utf16, 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);
+ }
+ else
+ {
+ char name_ansi[MAX_PATH];
+
+ if (filename_to_ansi (name, name_ansi) != 0)
+ return -1; /* errno set by filename_to_ansi */
+
+ fh = CreateFileA (name_ansi, FILE_WRITE_ATTRIBUTES,
+ 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);
}
else
{
- errno = EINVAL;
+ DWORD err = GetLastError ();
+
+ switch (err)
+ {
+ case ERROR_FILE_NOT_FOUND:
+ case ERROR_PATH_NOT_FOUND:
+ case ERROR_INVALID_DRIVE:
+ case ERROR_BAD_NETPATH:
+ case ERROR_DEV_NOT_EXIST:
+ /* ERROR_INVALID_NAME is the error CreateFile sets when the
+ file name includes ?s, i.e. translation to ANSI failed. */
+ case ERROR_INVALID_NAME:
+ errno = ENOENT;
+ break;
+ case ERROR_TOO_MANY_OPEN_FILES:
+ errno = ENFILE;
+ break;
+ case ERROR_ACCESS_DENIED:
+ case ERROR_SHARING_VIOLATION:
+ errno = EACCES;
+ break;
+ default:
+ errno = EINVAL;
+ break;
+ }
return -1;
}
return 0;
{
/* 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)
{
/* Decode the command name from locale-specific
encoding. */
- cmd_str = make_unibyte_string (pe.szExeFile,
- strlen (pe.szExeFile));
+ cmd_str = build_unibyte_string (pe.szExeFile);
+
decoded_cmd =
code_convert_string_norecord (cmd_str,
Vlocale_coding_system, 0);
{
if (winsock_lib != NULL && winsock_inuse == 0)
{
+ release_listen_threads ();
/* Not sure what would cause WSAENETDOWN, or even if it can happen
after WSAStartup returns successfully, but it seems reasonable
to allow unloading winsock anyway in that case. */
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)
{
- errno = h_errno = ENETDOWN;
+ errno = ENETDOWN;
return INVALID_SOCKET;
}
s = pfn_socket (af, type, protocol);
if (s != INVALID_SOCKET)
- {
- int retval = socket_to_fd (s);
-
- if (retval == -1)
- errno = h_errno;
- return retval;
- }
+ return socket_to_fd (s);
set_errno ();
return -1;
/* clean up */
_close (fd);
}
+ else
pfn_closesocket (s);
- h_errno = EMFILE;
+ errno = EMFILE;
return -1;
}
{
if (winsock_lib == NULL)
{
- errno = h_errno = ENOTSOCK;
+ errno = ENOTSOCK;
return SOCKET_ERROR;
}
set_errno ();
return rc;
}
- errno = h_errno = ENOTSOCK;
+ errno = ENOTSOCK;
return SOCKET_ERROR;
}
{
if (winsock_lib == NULL)
{
- errno = h_errno = ENOTSOCK;
+ errno = ENOTSOCK;
return SOCKET_ERROR;
}
set_errno ();
return rc;
}
- errno = 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);
- errno = 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)
{
- errno = 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)
{
- errno = h_errno = ENETDOWN;
+ errno = ENETDOWN;
return NULL;
}
{
if (winsock_lib == NULL)
{
- errno = h_errno = ENETDOWN;
+ errno = ENETDOWN;
return SOCKET_ERROR;
}
set_errno ();
return rc;
}
- errno = h_errno = ENOTSOCK;
+ errno = ENOTSOCK;
return SOCKET_ERROR;
}
{
if (winsock_lib == NULL)
{
- errno = h_errno = ENETDOWN;
+ errno = ENETDOWN;
return SOCKET_ERROR;
}
set_errno ();
return rc;
}
- errno = h_errno = ENOTSOCK;
+ errno = ENOTSOCK;
return SOCKET_ERROR;
}
{
if (winsock_lib == NULL)
{
- errno = h_errno = ENETDOWN;
+ errno = ENETDOWN;
return SOCKET_ERROR;
}
set_errno ();
return rc;
}
- errno = h_errno = ENOTSOCK;
+ errno = ENOTSOCK;
return SOCKET_ERROR;
}
{
if (winsock_lib == NULL)
{
- errno = h_errno = ENETDOWN;
+ errno = ENETDOWN;
return SOCKET_ERROR;
}
fd_info[s].flags |= FILE_LISTEN;
return rc;
}
- errno = h_errno = ENOTSOCK;
+ errno = ENOTSOCK;
return SOCKET_ERROR;
}
{
if (winsock_lib == NULL)
{
- errno = h_errno = ENETDOWN;
+ errno = ENETDOWN;
return SOCKET_ERROR;
}
set_errno ();
return rc;
}
- errno = h_errno = ENOTSOCK;
+ errno = ENOTSOCK;
return SOCKET_ERROR;
}
{
if (winsock_lib == NULL)
{
- errno = h_errno = ENETDOWN;
+ errno = ENETDOWN;
return -1;
}
if (t == INVALID_SOCKET)
set_errno ();
else
- {
- fd = socket_to_fd (t);
- if (fd < 0)
- errno = h_errno; /* socket_to_fd sets h_errno */
- }
+ fd = socket_to_fd (t);
if (fd >= 0)
{
}
return fd;
}
- errno = h_errno = ENOTSOCK;
+ errno = ENOTSOCK;
return -1;
}
{
if (winsock_lib == NULL)
{
- errno = h_errno = ENETDOWN;
+ errno = ENETDOWN;
return SOCKET_ERROR;
}
set_errno ();
return rc;
}
- errno = h_errno = ENOTSOCK;
+ errno = ENOTSOCK;
return SOCKET_ERROR;
}
{
if (winsock_lib == NULL)
{
- errno = h_errno = ENETDOWN;
+ errno = ENETDOWN;
return SOCKET_ERROR;
}
set_errno ();
return rc;
}
- errno = h_errno = ENOTSOCK;
+ errno = ENOTSOCK;
return SOCKET_ERROR;
}
/* Windows does not have an fcntl function. Provide an implementation
- solely for making sockets non-blocking. */
+ good enough for Emacs. */
int
fcntl (int s, int cmd, int options)
{
+ /* In the w32 Emacs port, fcntl (fd, F_DUPFD_CLOEXEC, fd1) is always
+ invoked in a context where fd1 is closed and all descriptors less
+ than fd1 are open, so sys_dup is an adequate implementation. */
+ if (cmd == F_DUPFD_CLOEXEC)
+ return sys_dup (s);
+
if (winsock_lib == NULL)
{
- errno = 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;
}
}
- errno = 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;
}
}
}
return rc;
}
-/* Unix pipe() has only one arg */
int
-sys_pipe (int * phandles)
+pipe2 (int * phandles, int pipe2_flags)
{
int rc;
unsigned flags;
+ eassert (pipe2_flags == O_CLOEXEC);
+
/* make pipe handles non-inheritable; when we spawn a child, we
replace the relevant handle with an inheritable one. Also put
pipes into binary mode; we will do text mode translation ourselves
}
/* 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)
{
rc = pfn_WSAEventSelect (SOCK_HANDLE (fd), hEv, FD_ACCEPT);
if (rc != SOCKET_ERROR)
{
- rc = WaitForSingleObject (hEv, INFINITE);
+ do {
+ rc = WaitForSingleObject (hEv, 500);
+ Sleep (5);
+ } while (rc == WAIT_TIMEOUT
+ && cp->status != STATUS_READ_ERROR
+ && cp->char_avail);
pfn_WSAEventSelect (SOCK_HANDLE (fd), NULL, 0);
if (rc == WAIT_OBJECT_0)
cp->status = STATUS_READ_SUCCEEDED;
pfn_ioctlsocket (SOCK_HANDLE (fd), FIONREAD, &waiting);
if (waiting == 0 && nchars == 0)
{
- h_errno = errno = EWOULDBLOCK;
+ errno = EWOULDBLOCK;
return -1;
}
return nchars;
}
+\f
+/* Emulation of SIOCGIFCONF and getifaddrs, see process.c. */
+
+extern Lisp_Object conv_sockaddr_to_lisp (struct sockaddr *, int);
+
+/* Return information about network interface IFNAME, or about all
+ interfaces (if IFNAME is nil). */
+static Lisp_Object
+network_interface_get_info (Lisp_Object ifname)
+{
+ ULONG ainfo_len = sizeof (IP_ADAPTER_INFO);
+ IP_ADAPTER_INFO *adapter, *ainfo = xmalloc (ainfo_len);
+ DWORD retval = get_adapters_info (ainfo, &ainfo_len);
+ Lisp_Object res = Qnil;
+
+ if (retval == ERROR_BUFFER_OVERFLOW)
+ {
+ ainfo = xrealloc (ainfo, ainfo_len);
+ retval = get_adapters_info (ainfo, &ainfo_len);
+ }
+
+ if (retval == ERROR_SUCCESS)
+ {
+ int eth_count = 0, tr_count = 0, fddi_count = 0, ppp_count = 0;
+ int sl_count = 0, wlan_count = 0, lo_count = 0, ifx_count = 0;
+ int if_num;
+ struct sockaddr_in sa;
+
+ /* For the below, we need some winsock functions, so make sure
+ the winsock DLL is loaded. If we cannot successfully load
+ it, they will have no use of the information we provide,
+ anyway, so punt. */
+ if (!winsock_lib && !init_winsock (1))
+ goto done;
+
+ for (adapter = ainfo; adapter; adapter = adapter->Next)
+ {
+ char namebuf[MAX_ADAPTER_NAME_LENGTH + 4];
+ u_long ip_addr;
+ /* Present Unix-compatible interface names, instead of the
+ Windows names, which are really GUIDs not readable by
+ humans. */
+ static const char *ifmt[] = {
+ "eth%d", "tr%d", "fddi%d", "ppp%d", "sl%d", "wlan%d",
+ "lo", "ifx%d"
+ };
+ enum {
+ NONE = -1,
+ ETHERNET = 0,
+ TOKENRING = 1,
+ FDDI = 2,
+ PPP = 3,
+ SLIP = 4,
+ WLAN = 5,
+ LOOPBACK = 6,
+ OTHER_IF = 7
+ } ifmt_idx;
+
+ switch (adapter->Type)
+ {
+ case MIB_IF_TYPE_ETHERNET:
+ /* Windows before Vista reports wireless adapters as
+ Ethernet. Work around by looking at the Description
+ string. */
+ if (strstr (adapter->Description, "Wireless "))
+ {
+ ifmt_idx = WLAN;
+ if_num = wlan_count++;
+ }
+ else
+ {
+ ifmt_idx = ETHERNET;
+ if_num = eth_count++;
+ }
+ break;
+ case MIB_IF_TYPE_TOKENRING:
+ ifmt_idx = TOKENRING;
+ if_num = tr_count++;
+ break;
+ case MIB_IF_TYPE_FDDI:
+ ifmt_idx = FDDI;
+ if_num = fddi_count++;
+ break;
+ case MIB_IF_TYPE_PPP:
+ ifmt_idx = PPP;
+ if_num = ppp_count++;
+ break;
+ case MIB_IF_TYPE_SLIP:
+ ifmt_idx = SLIP;
+ if_num = sl_count++;
+ break;
+ case IF_TYPE_IEEE80211:
+ ifmt_idx = WLAN;
+ if_num = wlan_count++;
+ break;
+ case MIB_IF_TYPE_LOOPBACK:
+ if (lo_count < 0)
+ {
+ ifmt_idx = LOOPBACK;
+ if_num = lo_count++;
+ }
+ else
+ ifmt_idx = NONE;
+ break;
+ default:
+ ifmt_idx = OTHER_IF;
+ if_num = ifx_count++;
+ break;
+ }
+ if (ifmt_idx == NONE)
+ continue;
+ sprintf (namebuf, ifmt[ifmt_idx], if_num);
+
+ sa.sin_family = AF_INET;
+ ip_addr = sys_inet_addr (adapter->IpAddressList.IpAddress.String);
+ if (ip_addr == INADDR_NONE)
+ {
+ /* Bogus address, skip this interface. */
+ continue;
+ }
+ sa.sin_addr.s_addr = ip_addr;
+ sa.sin_port = 0;
+ if (NILP (ifname))
+ res = Fcons (Fcons (build_string (namebuf),
+ conv_sockaddr_to_lisp ((struct sockaddr*) &sa,
+ sizeof (struct sockaddr))),
+ res);
+ else if (strcmp (namebuf, SSDATA (ifname)) == 0)
+ {
+ Lisp_Object hwaddr = Fmake_vector (make_number (6), Qnil);
+ register struct Lisp_Vector *p = XVECTOR (hwaddr);
+ Lisp_Object flags = Qnil;
+ int n;
+ u_long net_mask;
+
+ /* Flags. We guess most of them by type, since the
+ Windows flags are different and hard to get by. */
+ flags = Fcons (intern ("up"), flags);
+ if (ifmt_idx == ETHERNET || ifmt_idx == WLAN)
+ {
+ flags = Fcons (intern ("broadcast"), flags);
+ flags = Fcons (intern ("multicast"), flags);
+ }
+ flags = Fcons (intern ("running"), flags);
+ if (ifmt_idx == PPP)
+ {
+ flags = Fcons (intern ("pointopoint"), flags);
+ flags = Fcons (intern ("noarp"), flags);
+ }
+ if (adapter->HaveWins)
+ flags = Fcons (intern ("WINS"), flags);
+ if (adapter->DhcpEnabled)
+ flags = Fcons (intern ("dynamic"), flags);
+
+ res = Fcons (flags, res);
+
+ /* Hardware address and its family. */
+ for (n = 0; n < adapter->AddressLength; n++)
+ p->u.contents[n] = make_number ((int) adapter->Address[n]);
+ /* Windows does not support AF_LINK or AF_PACKET family
+ of addresses. Use an arbitrary family number that is
+ identical to what GNU/Linux returns. */
+ res = Fcons (Fcons (make_number (1), hwaddr), res);
+
+ /* Network mask. */
+ sa.sin_family = AF_INET;
+ net_mask = sys_inet_addr (adapter->IpAddressList.IpMask.String);
+ if (net_mask != INADDR_NONE)
+ {
+ sa.sin_addr.s_addr = net_mask;
+ sa.sin_port = 0;
+ res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
+ sizeof (struct sockaddr)),
+ res);
+ }
+ else
+ res = Fcons (Qnil, res);
+
+ sa.sin_family = AF_INET;
+ if (ip_addr != INADDR_NONE)
+ {
+ /* Broadcast address is only reported by
+ GetAdaptersAddresses, which is of limited
+ availability. Generate it on our own. */
+ u_long bcast_addr = (ip_addr & net_mask) | ~net_mask;
+
+ sa.sin_addr.s_addr = bcast_addr;
+ sa.sin_port = 0;
+ res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
+ sizeof (struct sockaddr)),
+ res);
+
+ /* IP address. */
+ sa.sin_addr.s_addr = ip_addr;
+ sa.sin_port = 0;
+ res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
+ sizeof (struct sockaddr)),
+ res);
+ }
+ else
+ res = Fcons (Qnil, Fcons (Qnil, res));
+ }
+ }
+ /* GetAdaptersInfo is documented to not report loopback
+ interfaces, so we generate one out of thin air. */
+ if (!lo_count)
+ {
+ sa.sin_family = AF_INET;
+ sa.sin_port = 0;
+ if (NILP (ifname))
+ {
+ sa.sin_addr.s_addr = sys_inet_addr ("127.0.0.1");
+ res = Fcons (Fcons (build_string ("lo"),
+ conv_sockaddr_to_lisp ((struct sockaddr*) &sa,
+ sizeof (struct sockaddr))),
+ res);
+ }
+ else if (strcmp (SSDATA (ifname), "lo") == 0)
+ {
+ res = Fcons (Fcons (intern ("running"),
+ Fcons (intern ("loopback"),
+ Fcons (intern ("up"), Qnil))), Qnil);
+ /* 772 is what 3 different GNU/Linux systems report for
+ the loopback interface. */
+ res = Fcons (Fcons (make_number (772),
+ Fmake_vector (make_number (6),
+ make_number (0))),
+ res);
+ sa.sin_addr.s_addr = sys_inet_addr ("255.0.0.0");
+ res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
+ sizeof (struct sockaddr)),
+ res);
+ sa.sin_addr.s_addr = sys_inet_addr ("0.0.0.0");
+ res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
+ sizeof (struct sockaddr)),
+ res);
+ sa.sin_addr.s_addr = sys_inet_addr ("127.0.0.1");
+ res = Fcons (conv_sockaddr_to_lisp ((struct sockaddr *) &sa,
+ sizeof (struct sockaddr)),
+ res);
+ }
+
+ }
+ }
+
+ done:
+ xfree (ainfo);
+ return res;
+}
+
+Lisp_Object
+network_interface_list (void)
+{
+ return network_interface_get_info (Qnil);
+}
+
+Lisp_Object
+network_interface_info (Lisp_Object ifname)
+{
+ return network_interface_get_info (ifname);
+}
+
+\f
/* The Windows CRT functions are "optimized for speed", so they don't
check for timezone and DST changes if they were last called less
than 1 minute ago (see http://support.microsoft.com/kb/821231). So
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;
+ g_b_init_get_adapters_info = 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;
+
+ /* If w32_unicode_filenames is non-zero, we will be using Unicode
+ (a.k.a. "wide") APIs to invoke functions that accept file
+ names. */
+ if (is_windows_9x ())
+ w32_unicode_filenames = 0;
+ else
+ w32_unicode_filenames = 1;
}
/* For make-serial-process */
int
-serial_open (char *port)
+serial_open (Lisp_Object port_obj)
{
+ char *port = SSDATA (port_obj);
HANDLE hnd;
child_process *cp;
int fd = -1;
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 timespec 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