X-Git-Url: http://git.hcoop.net/bpt/emacs.git/blobdiff_plain/7d9fb4de782c3ff316c6ffc26f6ea291be2f653b..6349f70a31a56fbaf8b5dbcaaddf624d137f9d63:/src/w32.c
diff --git a/src/w32.c b/src/w32.c
index 7d63c73eb1..46f36de8b9 100644
--- a/src/w32.c
+++ b/src/w32.c
@@ -19,6 +19,8 @@ along with GNU Emacs. If not, see . */
/*
Geoff Voelker (voelker@cs.washington.edu) 7-29-94
*/
+
+#include
#include /* for offsetof */
#include
#include
@@ -47,7 +49,6 @@ along with GNU Emacs. If not, see . */
#undef fopen
#undef link
#undef mkdir
-#undef mktemp
#undef open
#undef rename
#undef rmdir
@@ -90,6 +91,21 @@ typedef struct _MEMORY_STATUS_EX {
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
#include
@@ -202,6 +218,8 @@ typedef struct _REPARSE_DATA_BUFFER {
#undef recvfrom
#undef sendto
+#include /* should be after winsock2.h */
+
#include "w32.h"
#include
#include "w32common.h"
@@ -230,10 +248,12 @@ static int enable_privilege (LPCTSTR, BOOL, TOKEN_PRIVILEGES *);
static int restore_privilege (TOKEN_PRIVILEGES *);
static BOOL WINAPI revert_to_self (void);
-extern int sys_access (const char *, int);
+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);
+
@@ -278,6 +298,7 @@ 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
@@ -420,6 +441,9 @@ typedef BOOL (WINAPI *ConvertSecurityDescriptorToStringSecurityDescriptor_Proc)
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
@@ -1112,6 +1136,28 @@ convert_sddl_to_sd (LPCTSTR StringSecurityDescriptor,
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);
+}
+
/* Return 1 if P is a valid pointer to an object of size SIZE. Return
@@ -1136,7 +1182,193 @@ w32_valid_pointer_p (void *p, int size)
return -1;
}
-static char startup_dir[MAXPATHLEN];
+
+
+/* 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);
+}
+
+
+
+/* The directory where we started, in UTF-8. */
+static char startup_dir[MAX_UTF8_PATH];
/* Get the current working directory. */
char *
@@ -1328,8 +1560,8 @@ getloadavg (double loadavg[], int nelem)
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 =
{
@@ -1510,15 +1742,32 @@ init_user_info (void)
}
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)
@@ -1538,93 +1787,32 @@ srandom (int seed)
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, int multibyte)
+normalize_filename (register char *fp, char path_sep)
{
- 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;
+ 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')
{
@@ -1632,68 +1820,26 @@ normalize_filename (register char *fp, char path_sep, int multibyte)
fp += 2;
}
- if (multibyte || 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. MULTIBYTE non-zero
- means the file name is a multibyte string in Emacs's internal
- representation. */
+/* Destructively turn backslashes into slashes. */
void
-dostounix_filename (register char *p, int multibyte)
+dostounix_filename (register char *p)
{
- normalize_filename (p, '/', multibyte);
+ normalize_filename (p, '/');
}
/* Destructively turn slashes into backslashes. */
void
unixtodos_filename (register char *p)
{
- normalize_filename (p, '\\', 0);
+ normalize_filename (p, '\\');
}
/* Remove all CR's that are followed by a LF.
@@ -1726,9 +1872,9 @@ crlf_to_lf (register int n, register unsigned char *buf)
/* 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;
@@ -1744,17 +1890,13 @@ parse_root (char * name, char ** pPath)
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]))
@@ -1771,23 +1913,44 @@ parse_root (char * name, char ** pPath)
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;
}
@@ -1797,12 +1960,12 @@ w32_get_long_filename (char * name, char * buf, int size)
{
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. */
@@ -1810,7 +1973,7 @@ w32_get_long_filename (char * name, char * buf, int size)
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';
@@ -1819,7 +1982,7 @@ w32_get_long_filename (char * name, char * buf, int size)
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)
@@ -1843,6 +2006,29 @@ w32_get_long_filename (char * name, char * buf, int size)
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)
{
@@ -1851,7 +2037,7 @@ 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;
@@ -1951,8 +2137,6 @@ w32_get_resource (char *key, LPDWORD lpdwtype)
return (NULL);
}
-char *get_emacs_configuration (void);
-
void
init_environment (char ** argv)
{
@@ -1964,6 +2148,13 @@ 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
@@ -1979,8 +2170,8 @@ init_environment (char ** argv)
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. */
- if (tmp && faccessat (AT_FDCWD, tmp, D_OK, AT_EACCESS) == 0)
+ /* 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);
sprintf (var, "TMPDIR=%s", tmp);
@@ -2042,7 +2233,7 @@ init_environment (char ** argv)
/* For backwards compatibility, check if a .emacs file exists in C:/
If not, then we can try to default to the appdata directory under the
user's profile, which is more likely to be writable. */
- if (!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
@@ -2118,33 +2309,6 @@ init_environment (char ** argv)
_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)
- {
- *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));
- }
- }
- }
}
for (i = 0; i < N_ENV_VARS; i++)
@@ -2180,7 +2344,7 @@ init_environment (char ** argv)
strcpy (&fname[pend - pstart + 1], "cmdproxy.exe");
ExpandEnvironmentStrings ((LPSTR) fname, bufc,
sizeof (bufc));
- if (check_existing (bufc))
+ if (sys_access (bufc, F_OK) == 0)
{
lpval = bufc;
dwType = REG_SZ;
@@ -2260,8 +2424,22 @@ init_environment (char ** argv)
/* 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];
@@ -2284,175 +2462,23 @@ init_environment (char ** argv)
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, 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
/* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
int
-gettimeofday (struct timeval *restrict tv, struct timezone *restrict tz)
+gettimeofday (struct timeval *__restrict tv, struct timezone *__restrict tz)
{
struct _timeb tb;
_ftime (&tb);
@@ -2487,8 +2513,6 @@ gettimeofday (struct timeval *restrict tv, struct timezone *restrict tz)
int
fdutimens (int fd, char const *file, struct timespec const timespec[2])
{
- struct _utimbuf ut;
-
if (!timespec)
{
errno = ENOSYS;
@@ -2499,12 +2523,28 @@ fdutimens (int fd, char const *file, struct timespec const timespec[2])
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);
+ }
}
@@ -2588,6 +2628,7 @@ static void
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;
}
@@ -2600,14 +2641,30 @@ static volume_info_data *
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;
}
@@ -2646,20 +2703,47 @@ GetCachedVolumeInformation (char * root_dir)
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. */
@@ -2675,6 +2759,7 @@ GetCachedVolumeInformation (char * root_dir)
}
info->name = xstrdup (name);
+ unixtodos_filename (info->name);
info->serialnum = serialnum;
info->maxcomp = maxcomp;
info->flags = flags;
@@ -2697,53 +2782,23 @@ GetCachedVolumeInformation (char * root_dir)
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)
{
@@ -2765,18 +2820,19 @@ is_fat_volume (const char * name, const char ** pPath)
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, "?");
@@ -2843,7 +2899,7 @@ map_w32_filename (const char * name, const char ** pPath)
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--;
@@ -2878,25 +2934,28 @@ is_exec (const char * name)
xstrcasecmp (p, ".cmd") == 0));
}
-/* Emulate the Unix directory procedures opendir, closedir,
- and readdir. We can't use the procedures supplied in sysdep.c,
- so we provide them here. */
+/* Emulate the Unix directory procedures opendir, closedir, and
+ readdir. We rename them to sys_* names because some versions of
+ MinGW startup code call opendir and readdir to glob wildcards, and
+ the code that calls them doesn't grok UTF-8 encoded file names we
+ produce in dirent->d_name[]. */
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 WIN32_FIND_DATA dir_find_data;
+static char dir_pathname[MAX_UTF8_PATH];
+static WIN32_FIND_DATAW dir_find_data_w;
+static WIN32_FIND_DATAA dir_find_data_a;
/* Support shares on a network resource as subdirectories of a read-only
root directory. */
static HANDLE wnet_enum_handle = INVALID_HANDLE_VALUE;
static HANDLE open_unc_volume (const char *);
-static char *read_unc_volume (HANDLE, char *, int);
+static void *read_unc_volume (HANDLE, wchar_t *, char *, int);
static void close_unc_volume (HANDLE);
DIR *
-opendir (const char *filename)
+sys_opendir (const char *filename)
{
DIR *dirp;
@@ -2925,8 +2984,8 @@ opendir (const char *filename)
dirp->dd_loc = 0;
dirp->dd_size = 0;
- strncpy (dir_pathname, map_w32_filename (filename, NULL), MAXPATHLEN);
- dir_pathname[MAXPATHLEN] = '\0';
+ strncpy (dir_pathname, map_w32_filename (filename, NULL), MAX_UTF8_PATH - 1);
+ dir_pathname[MAX_UTF8_PATH - 1] = '\0';
/* Note: We don't support symlinks to file names on FAT volumes.
Doing so would mean punishing 99.99% of use cases by resolving
all the possible symlinks in FILENAME, recursively. */
@@ -2936,7 +2995,7 @@ opendir (const char *filename)
}
void
-closedir (DIR *dirp)
+sys_closedir (DIR *dirp)
{
/* If we have a find-handle open, close it. */
if (dir_find_handle != INVALID_HANDLE_VALUE)
@@ -2953,52 +3012,59 @@ closedir (DIR *dirp)
}
struct dirent *
-readdir (DIR *dirp)
+sys_readdir (DIR *dirp)
{
int downcase = !NILP (Vw32_downcase_file_names);
if (wnet_enum_handle != INVALID_HANDLE_VALUE)
{
if (!read_unc_volume (wnet_enum_handle,
- dir_find_data.cFileName,
+ dir_find_data_w.cFileName,
+ dir_find_data_a.cFileName,
MAX_PATH))
return NULL;
}
/* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
else if (dir_find_handle == INVALID_HANDLE_VALUE)
{
- char filename[MAXNAMLEN + 3];
+ char filename[MAX_UTF8_PATH + 2];
int ln;
- int dbcs_p = max_filename_mbslen () > 1;
strcpy (filename, dir_pathname);
ln = strlen (filename) - 1;
- if (!dbcs_p)
+ if (!IS_DIRECTORY_SEP (filename[ln]))
+ strcat (filename, "\\");
+ strcat (filename, "*");
+
+ /* Note: No need to resolve symlinks in FILENAME, because
+ FindFirst opens the directory that is the target of a
+ symlink. */
+ if (w32_unicode_filenames)
{
- if (!IS_DIRECTORY_SEP (filename[ln]))
- strcat (filename, "\\");
+ wchar_t fnw[MAX_PATH];
+
+ filename_to_utf16 (filename, fnw);
+ dir_find_handle = FindFirstFileW (fnw, &dir_find_data_w);
}
else
{
- char *end = filename + ln + 1;
- char *last_char = CharPrevExA (file_name_codepage, filename, end, 0);
+ char fna[MAX_PATH];
- if (!IS_DIRECTORY_SEP (*last_char))
- strcat (filename, "\\");
+ filename_to_ansi (filename, fna);
+ dir_find_handle = FindFirstFileA (fna, &dir_find_data_a);
}
- strcat (filename, "*");
-
- /* Note: No need to resolve symlinks in FILENAME, because
- FindFirst opens the directory that is the target of a
- symlink. */
- dir_find_handle = FindFirstFile (filename, &dir_find_data);
if (dir_find_handle == INVALID_HANDLE_VALUE)
return NULL;
}
+ else if (w32_unicode_filenames)
+ {
+ if (!FindNextFileW (dir_find_handle, &dir_find_data_w))
+ return NULL;
+ }
else
{
- if (!FindNextFile (dir_find_handle, &dir_find_data))
+ if (!FindNextFileA (dir_find_handle, &dir_find_data_a))
return NULL;
}
@@ -3006,112 +3072,153 @@ readdir (DIR *dirp)
value returned by stat(). */
dir_static.d_ino = 1;
- strcpy (dir_static.d_name, dir_find_data.cFileName);
-
- /* If the file name in cFileName[] includes `?' characters, it means
- the original file name used characters that cannot be represented
- by the current ANSI codepage. To avoid total lossage, retrieve
- the short 8+3 alias of the long file name. */
- if (_mbspbrk (dir_static.d_name, "?"))
+ if (w32_unicode_filenames)
{
- strcpy (dir_static.d_name, dir_find_data.cAlternateFileName);
- 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 dirent) - MAXNAMLEN + 3 +
- dir_static.d_namlen - dir_static.d_namlen % 4;
+ if (downcase || dir_is_fat)
+ {
+ wchar_t tem[MAX_PATH];
- /* If the file name in cFileName[] includes `?' characters, it means
- the original file name used characters that cannot be represented
- by the current ANSI codepage. To avoid total lossage, retrieve
- the short 8+3 alias of the long file name. */
- if (_mbspbrk (dir_find_data.cFileName, "?"))
- {
- strcpy (dir_static.d_name, dir_find_data.cAlternateFileName);
- /* 8+3 aliases are returned in all caps, which could break
- various alists that look at filenames' extensions. */
- downcase = 1;
+ wcscpy (tem, dir_find_data_w.cFileName);
+ CharLowerW (tem);
+ filename_from_utf16 (tem, dir_static.d_name);
+ }
+ else
+ filename_from_utf16 (dir_find_data_w.cFileName, dir_static.d_name);
}
else
- strcpy (dir_static.d_name, dir_find_data.cFileName);
- dir_static.d_namlen = strlen (dir_static.d_name);
- if (dir_is_fat)
- _mbslwr (dir_static.d_name);
- else if (downcase)
{
- register char *p;
- int dbcs_p = max_filename_mbslen () > 1;
- for (p = dir_static.d_name; *p; )
+ char tem[MAX_PATH];
+
+ /* If the file name in cFileName[] includes `?' characters, it
+ means the original file name used characters that cannot be
+ represented by the current ANSI codepage. To avoid total
+ lossage, retrieve the short 8+3 alias of the long file
+ name. */
+ if (_mbspbrk (dir_find_data_a.cFileName, "?"))
{
- if (*p >= 'a' && *p <= 'z')
- break;
- if (dbcs_p)
- p = CharNextExA (file_name_codepage, p, 0);
- else
- p++;
+ strcpy (tem, dir_find_data_a.cAlternateFileName);
+ /* 8+3 aliases are returned in all caps, which could break
+ various alists that look at filenames' extensions. */
+ downcase = 1;
+ }
+ else if (downcase || dir_is_fat)
+ strcpy (tem, dir_find_data_a.cFileName);
+ else
+ filename_from_ansi (dir_find_data_a.cFileName, dir_static.d_name);
+ if (downcase || dir_is_fat)
+ {
+ _mbslwr (tem);
+ filename_from_ansi (tem, dir_static.d_name);
}
- if (!*p)
- _mbslwr (dir_static.d_name);
}
+ dir_static.d_namlen = strlen (dir_static.d_name);
+ dir_static.d_reclen = sizeof (struct dirent) - MAX_UTF8_PATH + 3 +
+ dir_static.d_namlen - dir_static.d_namlen % 4;
+
return &dir_static;
}
static HANDLE
open_unc_volume (const char *path)
{
- NETRESOURCE nr;
+ const char *fn = map_w32_filename (path, NULL);
+ DWORD result;
HANDLE henum;
- int result;
- nr.dwScope = RESOURCE_GLOBALNET;
- nr.dwType = RESOURCETYPE_DISK;
- nr.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
- nr.dwUsage = RESOURCEUSAGE_CONTAINER;
- nr.lpLocalName = NULL;
- nr.lpRemoteName = (LPSTR)map_w32_filename (path, NULL);
- nr.lpComment = NULL;
- nr.lpProvider = NULL;
+ if (w32_unicode_filenames)
+ {
+ NETRESOURCEW nrw;
+ wchar_t fnw[MAX_PATH];
+
+ nrw.dwScope = RESOURCE_GLOBALNET;
+ nrw.dwType = RESOURCETYPE_DISK;
+ nrw.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
+ nrw.dwUsage = RESOURCEUSAGE_CONTAINER;
+ nrw.lpLocalName = NULL;
+ filename_to_utf16 (fn, fnw);
+ nrw.lpRemoteName = fnw;
+ nrw.lpComment = NULL;
+ nrw.lpProvider = NULL;
- result = WNetOpenEnum (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
- RESOURCEUSAGE_CONNECTABLE, &nr, &henum);
+ result = WNetOpenEnumW (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
+ RESOURCEUSAGE_CONNECTABLE, &nrw, &henum);
+ }
+ else
+ {
+ NETRESOURCEA nra;
+ char fna[MAX_PATH];
+
+ nra.dwScope = RESOURCE_GLOBALNET;
+ nra.dwType = RESOURCETYPE_DISK;
+ nra.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
+ nra.dwUsage = RESOURCEUSAGE_CONTAINER;
+ nra.lpLocalName = NULL;
+ filename_to_ansi (fn, fna);
+ nra.lpRemoteName = fna;
+ nra.lpComment = NULL;
+ nra.lpProvider = NULL;
+ result = WNetOpenEnumA (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
+ RESOURCEUSAGE_CONNECTABLE, &nra, &henum);
+ }
if (result == NO_ERROR)
return henum;
else
return INVALID_HANDLE_VALUE;
}
-static char *
-read_unc_volume (HANDLE henum, char *readbuf, int size)
+static void *
+read_unc_volume (HANDLE henum, wchar_t *fname_w, char *fname_a, int size)
{
DWORD count;
int result;
- DWORD bufsize = 512;
char *buffer;
- char *ptr;
- int dbcs_p = max_filename_mbslen () > 1;
+ DWORD bufsize = 512;
+ void *retval;
count = 1;
- buffer = alloca (bufsize);
- result = WNetEnumResource (henum, &count, buffer, &bufsize);
- if (result != NO_ERROR)
- return NULL;
+ if (w32_unicode_filenames)
+ {
+ wchar_t *ptrw;
- /* WNetEnumResource returns \\resource\share...skip forward to "share". */
- ptr = ((LPNETRESOURCE) buffer)->lpRemoteName;
- ptr += 2;
- if (!dbcs_p)
- while (*ptr && !IS_DIRECTORY_SEP (*ptr)) ptr++;
+ bufsize *= 2;
+ buffer = alloca (bufsize);
+ result = WNetEnumResourceW (henum, &count, buffer, &bufsize);
+ if (result != NO_ERROR)
+ return NULL;
+ /* WNetEnumResource returns \\resource\share...skip forward to "share". */
+ ptrw = ((LPNETRESOURCEW) buffer)->lpRemoteName;
+ ptrw += 2;
+ while (*ptrw && *ptrw != L'/' && *ptrw != L'\\') ptrw++;
+ ptrw++;
+ wcsncpy (fname_w, ptrw, size);
+ retval = fname_w;
+ }
else
{
- while (*ptr && !IS_DIRECTORY_SEP (*ptr))
- ptr = CharNextExA (file_name_codepage, ptr, 0);
+ int dbcs_p = max_filename_mbslen () > 1;
+ char *ptra;
+
+ buffer = alloca (bufsize);
+ result = WNetEnumResourceA (henum, &count, buffer, &bufsize);
+ if (result != NO_ERROR)
+ return NULL;
+ ptra = ((LPNETRESOURCEA) buffer)->lpRemoteName;
+ ptra += 2;
+ if (!dbcs_p)
+ while (*ptra && !IS_DIRECTORY_SEP (*ptra)) ptra++;
+ else
+ {
+ while (*ptra && !IS_DIRECTORY_SEP (*ptra))
+ ptra = CharNextExA (file_name_codepage, ptra, 0);
+ }
+ ptra++;
+ strncpy (fname_a, ptra, size);
+ retval = fname_a;
}
- ptr++;
- strncpy (readbuf, ptr, size);
- return readbuf;
+ return retval;
}
static void
@@ -3142,13 +3249,12 @@ unc_volume_file_attributes (const char *path)
static void
logon_network_drive (const char *path)
{
- NETRESOURCE resource;
- char share[MAX_PATH];
+ char share[MAX_UTF8_PATH];
int n_slashes;
char drive[4];
UINT drvtype;
char *p;
- int dbcs_p;
+ DWORD val;
if (IS_DIRECTORY_SEP (path[0]) && IS_DIRECTORY_SEP (path[1]))
drvtype = DRIVE_REMOTE;
@@ -3168,28 +3274,70 @@ logon_network_drive (const char *path)
return;
n_slashes = 2;
- strncpy (share, path, MAX_PATH);
+ strncpy (share, path, MAX_UTF8_PATH);
/* Truncate to just server and share name. */
- dbcs_p = max_filename_mbslen () > 1;
- for (p = share + 2; *p && p < share + MAX_PATH; )
+ for (p = share + 2; *p && p < share + MAX_UTF8_PATH; p++)
{
if (IS_DIRECTORY_SEP (*p) && ++n_slashes > 3)
{
*p = '\0';
break;
}
- if (dbcs_p)
- p = CharNextExA (file_name_codepage, p, 0);
- else
- p++;
}
- resource.dwType = RESOURCETYPE_DISK;
- resource.lpLocalName = NULL;
- resource.lpRemoteName = share;
- resource.lpProvider = NULL;
+ if (w32_unicode_filenames)
+ {
+ NETRESOURCEW resourcew;
+ wchar_t share_w[MAX_PATH];
+
+ resourcew.dwScope = RESOURCE_GLOBALNET;
+ resourcew.dwType = RESOURCETYPE_DISK;
+ resourcew.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
+ resourcew.dwUsage = RESOURCEUSAGE_CONTAINER;
+ resourcew.lpLocalName = NULL;
+ filename_to_utf16 (share, share_w);
+ resourcew.lpRemoteName = share_w;
+ resourcew.lpProvider = NULL;
+
+ val = WNetAddConnection2W (&resourcew, NULL, NULL, CONNECT_INTERACTIVE);
+ }
+ else
+ {
+ NETRESOURCEA resourcea;
+ char share_a[MAX_PATH];
+
+ resourcea.dwScope = RESOURCE_GLOBALNET;
+ resourcea.dwType = RESOURCETYPE_DISK;
+ resourcea.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
+ resourcea.dwUsage = RESOURCEUSAGE_CONTAINER;
+ resourcea.lpLocalName = NULL;
+ filename_to_ansi (share, share_a);
+ resourcea.lpRemoteName = share_a;
+ resourcea.lpProvider = NULL;
- WNetAddConnection2 (&resource, NULL, NULL, CONNECT_INTERACTIVE);
+ val = WNetAddConnection2A (&resourcea, NULL, NULL, CONNECT_INTERACTIVE);
+ }
+
+ switch (val)
+ {
+ case NO_ERROR:
+ case ERROR_ALREADY_ASSIGNED:
+ break;
+ case ERROR_ACCESS_DENIED:
+ case ERROR_LOGON_FAILURE:
+ errno = EACCES;
+ break;
+ case ERROR_BUSY:
+ errno = EAGAIN;
+ break;
+ case ERROR_BAD_NET_NAME:
+ case ERROR_NO_NET_OR_BAD_PATH:
+ case ERROR_NO_NETWORK:
+ case ERROR_CANCELLED:
+ default:
+ errno = ENOENT;
+ break;
+ }
}
/* Emulate faccessat(2). */
@@ -3217,7 +3365,22 @@ faccessat (int dirfd, const char * path, int mode, int flags)
&& (flags & AT_SYMLINK_NOFOLLOW) == 0)
path = chase_symlinks (path);
- if ((attributes = GetFileAttributes (path)) == -1)
+ if (w32_unicode_filenames)
+ {
+ wchar_t path_w[MAX_PATH];
+
+ filename_to_utf16 (path, path_w);
+ attributes = GetFileAttributesW (path_w);
+ }
+ else
+ {
+ char path_a[MAX_PATH];
+
+ filename_to_ansi (path, path_a);
+ attributes = GetFileAttributesA (path_a);
+ }
+
+ if (attributes == -1)
{
DWORD w32err = GetLastError ();
@@ -3265,6 +3428,62 @@ faccessat (int dirfd, const char * path, int mode, int flags)
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;
+ }
+ 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;
+}
+
/* 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
@@ -3273,20 +3492,63 @@ faccessat (int dirfd, const char * path, int mode, int flags)
int
sys_chdir (const char * path)
{
- return _chdir (map_w32_filename (path, NULL));
+ path = map_w32_filename (path, NULL);
+ if (w32_unicode_filenames)
+ {
+ wchar_t newdir_w[MAX_PATH];
+
+ if (filename_to_utf16 (path, newdir_w) == 0)
+ return _wchdir (newdir_w);
+ return -1;
+ }
+ else
+ {
+ char newdir_a[MAX_PATH];
+
+ if (filename_to_ansi (path, newdir_a) == 0)
+ return _chdir (newdir_a);
+ return -1;
+ }
}
int
sys_chmod (const char * path, int mode)
{
path = chase_symlinks (map_w32_filename (path, NULL));
- return _chmod (path, mode);
+ if (w32_unicode_filenames)
+ {
+ wchar_t path_w[MAX_PATH];
+
+ filename_to_utf16 (path, path_w);
+ return _wchmod (path_w, mode);
+ }
+ else
+ {
+ char path_a[MAX_PATH];
+
+ filename_to_ansi (path, path_a);
+ return _chmod (path_a, mode);
+ }
}
int
sys_creat (const char * path, int mode)
{
- return _creat (map_w32_filename (path, NULL), mode);
+ path = map_w32_filename (path, NULL);
+ if (w32_unicode_filenames)
+ {
+ wchar_t path_w[MAX_PATH];
+
+ filename_to_utf16 (path, path_w);
+ return _wcreat (path_w, mode);
+ }
+ else
+ {
+ char path_a[MAX_PATH];
+
+ filename_to_ansi (path, path_a);
+ return _creat (path_a, mode);
+ }
}
FILE *
@@ -3326,7 +3588,21 @@ sys_fopen (const char * path, const char * mode)
}
else break;
- fd = _open (map_w32_filename (path, NULL), oflag | _O_NOINHERIT, 0644);
+ path = map_w32_filename (path, NULL);
+ if (w32_unicode_filenames)
+ {
+ wchar_t path_w[MAX_PATH];
+
+ filename_to_utf16 (path, path_w);
+ fd = _wopen (path_w, oflag | _O_NOINHERIT, 0644);
+ }
+ else
+ {
+ char path_a[MAX_PATH];
+
+ filename_to_ansi (path, path_a);
+ fd = _open (path_a, oflag | _O_NOINHERIT, 0644);
+ }
if (fd < 0)
return NULL;
@@ -3339,7 +3615,9 @@ sys_link (const char * old, const char * new)
{
HANDLE fileh;
int result = -1;
- char oldname[MAX_PATH], newname[MAX_PATH];
+ char oldname[MAX_UTF8_PATH], newname[MAX_UTF8_PATH];
+ wchar_t oldname_w[MAX_PATH];
+ char oldname_a[MAX_PATH];
if (old == NULL || new == NULL)
{
@@ -3350,8 +3628,18 @@ sys_link (const char * old, const char * new)
strcpy (oldname, map_w32_filename (old, NULL));
strcpy (newname, map_w32_filename (new, NULL));
- fileh = CreateFile (oldname, 0, 0, NULL, OPEN_EXISTING,
- FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ if (w32_unicode_filenames)
+ {
+ filename_to_utf16 (oldname, oldname_w);
+ fileh = CreateFileW (oldname_w, 0, 0, NULL, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ }
+ else
+ {
+ filename_to_ansi (oldname, oldname_a);
+ fileh = CreateFileA (oldname_a, 0, 0, NULL, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ }
if (fileh != INVALID_HANDLE_VALUE)
{
int wlen;
@@ -3368,7 +3656,10 @@ sys_link (const char * old, const char * new)
WCHAR wbuffer[MAX_PATH]; /* extra space for link name */
} data;
- wlen = MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, newname, -1,
+ /* We used to pass MB_PRECOMPOSED as the 2nd arg here, but MSDN
+ indicates that flag is unsupported for CP_UTF8, and OTOH says
+ it is the default anyway. */
+ wlen = MultiByteToWideChar (CP_UTF8, 0, newname, -1,
data.wid.cStreamName, MAX_PATH);
if (wlen > 0)
{
@@ -3392,9 +3683,40 @@ sys_link (const char * old, const char * new)
}
else
{
- /* Should try mapping GetLastError to errno; for now just
- indicate a general error (eg. links not supported). */
- errno = EINVAL; // perhaps EMLINK?
+ DWORD err = GetLastError ();
+ DWORD attributes;
+
+ switch (err)
+ {
+ case ERROR_ACCESS_DENIED:
+ /* This is what happens when OLDNAME is a directory,
+ since Windows doesn't support hard links to
+ directories. Posix says to set errno to EPERM in
+ that case. */
+ if (w32_unicode_filenames)
+ attributes = GetFileAttributesW (oldname_w);
+ else
+ attributes = GetFileAttributesA (oldname_a);
+ if (attributes != -1
+ && (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
+ errno = EPERM;
+ else if (attributes == -1
+ && is_unc_volume (oldname)
+ && unc_volume_file_attributes (oldname) != -1)
+ errno = EPERM;
+ else
+ errno = EACCES;
+ break;
+ case ERROR_TOO_MANY_LINKS:
+ errno = EMLINK;
+ break;
+ case ERROR_NOT_SAME_DEVICE:
+ errno = EXDEV;
+ break;
+ default:
+ errno = EINVAL;
+ break;
+ }
}
}
@@ -3412,25 +3734,46 @@ sys_mkdir (const char * path)
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 */
@@ -3445,38 +3788,22 @@ sys_mktemp (char * template)
i = 0;
do
{
- int save_errno = errno;
p[0] = first_char[i];
- if (faccessat (AT_FDCWD, template, F_OK, AT_EACCESS) < 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;
-}
-
-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;
+ /* Template is badly formed or else we can't generate a unique name. */
+ return -1;
}
int
@@ -3686,49 +4013,6 @@ convert_from_time_t (time_t time, FILETIME * pft)
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)
{
@@ -3785,12 +4069,6 @@ get_rid (PSID sid)
/* 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;
@@ -4252,7 +4530,7 @@ stat_worker (const char * path, struct stat * buf, int follow_symlinks)
&& xstrcasecmp (name + len + 1, dir_static.d_name) == 0)
{
/* This was the last entry returned by readdir. */
- wfd = dir_find_data;
+ wfd = dir_find_data_a; /* FIXME!!! */
}
else
{
@@ -4486,6 +4764,9 @@ fstat (int desc, struct stat * buf)
return 0;
}
+/* A version of 'utime' which handles directories as well as
+ files. */
+
int
utime (const char *name, struct utimbuf *times)
{
@@ -4500,13 +4781,32 @@ 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);
@@ -4521,7 +4821,31 @@ utime (const char *name, struct utimbuf *times)
}
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;
@@ -5754,8 +6078,8 @@ system_process_attributes (Lisp_Object pid)
{
/* 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);
@@ -6060,6 +6384,7 @@ term_winsock (void)
{
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. */
@@ -6725,10 +7050,16 @@ sys_sendto (int s, const char * buf, int len, int flags,
}
/* 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 = ENETDOWN;
@@ -6870,13 +7201,14 @@ sys_dup2 (int src, int dst)
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
@@ -7037,7 +7369,12 @@ _sys_wait_accept (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;
@@ -7387,6 +7724,269 @@ sys_write (int fd, const void * buffer, unsigned int count)
return nchars;
}
+
+/* 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);
+}
+
+
/* 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
@@ -7688,6 +8288,7 @@ globals_of_w32 (void)
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
@@ -7700,12 +8301,21 @@ globals_of_w32 (void)
/* 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;
@@ -7899,7 +8509,7 @@ emacs_gnutls_pull (gnutls_transport_ptr_t p, void* buf, size_t sz)
{
int n, err;
SELECT_TYPE fdset;
- EMACS_TIME timeout;
+ struct timespec timeout;
struct Lisp_Process *process = (struct Lisp_Process *)p;
int fd = process->infd;