summaryrefslogtreecommitdiff
path: root/win32
diff options
context:
space:
mode:
Diffstat (limited to 'win32')
-rw-r--r--win32/Makefile.sub21
-rw-r--r--win32/README.win326
-rw-r--r--win32/file.c715
-rwxr-xr-xwin32/makedirs.bat3
-rwxr-xr-xwin32/mkexports.rb6
-rwxr-xr-x[-rw-r--r--]win32/rmall.bat0
-rw-r--r--win32/win32.c264
7 files changed, 877 insertions, 138 deletions
diff --git a/win32/Makefile.sub b/win32/Makefile.sub
index 3733dc8..135c2db 100644
--- a/win32/Makefile.sub
+++ b/win32/Makefile.sub
@@ -74,6 +74,7 @@ RM = $(COMSPEC) /C $(srcdir:/=\)\win32\rm.bat
RMDIR = $(COMSPEC) /C $(srcdir:/=\)\win32\rmdirs.bat
RMDIRS = $(COMSPEC) /C $(srcdir:/=\)\win32\rmdirs.bat
RMALL = $(COMSPEC) /C $(srcdir:/=\)\win32\rmall.bat
+MAKEDIRS = $(COMSPEC) /E:ON /C $(srcdir:/=\)\win32\makedirs.bat
CP = copy > nul
MV = move > nul
!if !defined(BASERUBY)
@@ -122,6 +123,9 @@ PLATFORM = mswin32
!ifdef NTVER
ARCHDEFS = -D_WIN32_WINNT=$(NTVER) $(ARCHDEFS)
!endif
+!if !defined(PLATFORM_DIR)
+PLATFORM_DIR = win32
+!endif
arch = $(ARCH)-$(PLATFORM)
sitearch = $(ARCH)-$(RT)
@@ -219,13 +223,13 @@ RFLAGS = -r
EXTLIBS =
!endif
!if !defined(LIBS)
-LIBS = oldnames.lib user32.lib advapi32.lib shell32.lib ws2_32.lib imagehlp.lib $(EXTLIBS)
+LIBS = oldnames.lib user32.lib advapi32.lib shell32.lib ws2_32.lib imagehlp.lib shlwapi.lib $(EXTLIBS)
!endif
!if "$(ENABLE_WIN95)" == "yes"
LIBS = unicows.lib $(LIBS)
!endif
!if !defined(MISSING)
-MISSING = acosh.obj cbrt.obj crypt.obj erf.obj ffs.obj langinfo.obj lgamma_r.obj strlcat.obj strlcpy.obj tgamma.obj win32.obj setproctitle.obj
+MISSING = acosh.obj cbrt.obj crypt.obj erf.obj ffs.obj langinfo.obj lgamma_r.obj strlcat.obj strlcpy.obj tgamma.obj win32/win32.obj win32/file.obj setproctitle.obj
!endif
ARFLAGS = -machine:$(MACHINE) -out:
@@ -286,8 +290,6 @@ DEFAULT_PRELUDES = $(NO_GEM_PRELUDE)
DEFAULT_PRELUDES = $(YES_GEM_PRELUDE)
!endif
-MAKEDIRS = $(MINIRUBY) -run -e mkdir -- -p
-
!if !defined(STACK)
!if "$(ARCH)" == "x64" || "$(ARCH)" == "ia64"
STACK = 0x400000
@@ -535,11 +537,13 @@ $(CONFIG_H): $(MKFILES) $(srcdir)/win32/Makefile.sub $(win_srcdir)/Makefile.sub
#define HAVE_FCNTL_H 1
#define HAVE_SYS_UTIME_H 1
#define HAVE_FLOAT_H 1
+#define HAVE_TIME_H 1
#define rb_pid_t int
#define rb_gid_t int
#define rb_uid_t int
#define HAVE_STRUCT_STAT_ST_RDEV 1
#define HAVE_ST_RDEV 1
+#define HAVE_STRUCT_TIMEVAL 1
!if $(MSC_VER) >= 1600
#define HAVE_STDINT_H 1
!else
@@ -593,7 +597,6 @@ $(CONFIG_H): $(MKFILES) $(srcdir)/win32/Makefile.sub $(win_srcdir)/Makefile.sub
#define GETGROUPS_T int
#define RETSIGTYPE void
#define TYPEOF_TIMEVAL_TV_SEC long
-#define GC_MARK_STACKFRAME_WORD 30
#define HAVE_ALLOCA 1
#define HAVE_DUP2 1
#define HAVE_MEMCMP 1
@@ -920,6 +923,10 @@ clean-rdoc distclean-rdoc realclean-rdoc:
clean-capi distclean-capi realclean-capi:
-$(Q)$(RMALL) $(CAPIOUT:/=\)
+clean-platform:
+ $(Q)$(RM) $(PLATFORM_D:/=\)
+ -$(Q)$(RMDIR) $(PLATFORM_DIR:/=\)
+
clean-ext distclean-ext realclean-ext::
!if "$(EXTS)" != ""
@for %I in ($(EXTS)) \
@@ -993,7 +1000,7 @@ $(ruby_pc): $(RBCONFIG)
{$(win_srcdir)/sys}.c.obj:
$(ECHO) compiling $(<:\=/)
$(Q) $(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) $(COUTFLAG)$@ -c -Tc$(<:\=/)
-{$(srcdir)}.c.obj:
+{$(srcdir)}.c{}.obj:
$(ECHO) compiling $(<:\=/)
$(Q) $(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) $(COUTFLAG)$@ -c -Tc$(<:\=/)
.c.obj:
@@ -1040,7 +1047,7 @@ enc/unicode/name2ctype.h: {$(srcdir)}enc/unicode/name2ctype.h.blt
$(OBJS): {$(hdrdir)/ruby}win32.h
-dir.$(OBJEXT) win32.$(OBJEXT): {$(srcdir)}win32/dir.h
+dir.$(OBJEXT) win32/win32.$(OBJEXT): {$(srcdir)}win32/dir.h
ext/extinit.obj: ext/extinit.c $(SETUP)
$(ECHO) compiling ext/extinit.c
diff --git a/win32/README.win32 b/win32/README.win32
index 0737f1b..f6a9a71 100644
--- a/win32/README.win32
+++ b/win32/README.win32
@@ -25,7 +25,11 @@
* sed
* ruby 1.8
-(5) If you want built binaries to run on Windows 95 series (including
+(5) Enable Command Extension of your command line. It's the default behavior
+ of cmd.exe. If you want to enable it explicitly, run cmd.exe with /E:ON
+ option.
+
+(6) If you want built binaries to run on Windows 95 series (including
98 and Me), you need unicows.lib at compile time, and unicows.dll
at run time.
diff --git a/win32/file.c b/win32/file.c
new file mode 100644
index 0000000..350f8da
--- /dev/null
+++ b/win32/file.c
@@ -0,0 +1,715 @@
+#include "ruby/ruby.h"
+#include "ruby/encoding.h"
+#include <winbase.h>
+#include <wchar.h>
+#include <shlwapi.h>
+
+#ifndef INVALID_FILE_ATTRIBUTES
+# define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
+#endif
+
+/* cache 'encoding name' => 'code page' into a hash */
+static VALUE rb_code_page;
+
+#define IS_DIR_SEPARATOR_P(c) (c == L'\\' || c == L'/')
+#define IS_DIR_UNC_P(c) (IS_DIR_SEPARATOR_P(c[0]) && IS_DIR_SEPARATOR_P(c[1]))
+
+/* MultiByteToWideChar() doesn't work with code page 51932 */
+#define INVALID_CODE_PAGE 51932
+#define PATH_BUFFER_SIZE MAX_PATH * 2
+
+#define insecure_obj_p(obj, level) ((level) >= 4 || ((level) > 0 && OBJ_TAINTED(obj)))
+
+static inline void
+replace_wchar(wchar_t *s, int find, int replace)
+{
+ while (*s != 0) {
+ if (*s == find)
+ *s = replace;
+ s++;
+ }
+}
+
+/* Convert str from multibyte char to wchar with specified code page */
+static inline void
+convert_mb_to_wchar(VALUE str, wchar_t **wstr, wchar_t **wstr_pos, size_t *wstr_len, UINT code_page)
+{
+ size_t len;
+
+ if (NIL_P(str))
+ return;
+
+ len = MultiByteToWideChar(code_page, 0, RSTRING_PTR(str), -1, NULL, 0) + 1;
+ *wstr = (wchar_t *)xmalloc(len * sizeof(wchar_t));
+ if (wstr_pos)
+ *wstr_pos = *wstr;
+
+ MultiByteToWideChar(code_page, 0, RSTRING_PTR(str), -1, *wstr, len);
+ *wstr_len = len - 2;
+}
+
+static inline void
+convert_wchar_to_mb(const wchar_t *wstr, char **str, size_t *str_len, UINT code_page)
+{
+ size_t len;
+
+ len = WideCharToMultiByte(code_page, 0, wstr, -1, NULL, 0, NULL, NULL);
+ *str = (char *)xmalloc(len * sizeof(char));
+ WideCharToMultiByte(code_page, 0, wstr, -1, *str, len, NULL, NULL);
+
+ /* do not count terminator as part of the string length */
+ *str_len = len - 1;
+}
+
+/*
+ Return user's home directory using environment variables combinations.
+ Memory allocated by this function should be manually freed afterwards.
+
+ Try:
+ HOME, HOMEDRIVE + HOMEPATH and USERPROFILE environment variables
+ TODO: Special Folders - Profile and Personal
+*/
+static wchar_t *
+home_dir(void)
+{
+ wchar_t *buffer = NULL;
+ size_t buffer_len = 0, len = 0;
+ size_t home_env = 0;
+
+ /*
+ GetEnvironmentVariableW when used with NULL will return the required
+ buffer size and its terminating character.
+ http://msdn.microsoft.com/en-us/library/windows/desktop/ms683188(v=vs.85).aspx
+ */
+
+ if (len = GetEnvironmentVariableW(L"HOME", NULL, 0)) {
+ buffer_len = len;
+ home_env = 1;
+ }
+ else if (len = GetEnvironmentVariableW(L"HOMEDRIVE", NULL, 0)) {
+ buffer_len = len;
+ if (len = GetEnvironmentVariableW(L"HOMEPATH", NULL, 0)) {
+ buffer_len += len;
+ home_env = 2;
+ }
+ else {
+ buffer_len = 0;
+ }
+ }
+ else if (len = GetEnvironmentVariableW(L"USERPROFILE", NULL, 0)) {
+ buffer_len = len;
+ home_env = 3;
+ }
+
+ /* allocate buffer */
+ if (home_env)
+ buffer = (wchar_t *)xmalloc(buffer_len * sizeof(wchar_t));
+
+ switch (home_env) {
+ case 1:
+ /* HOME */
+ GetEnvironmentVariableW(L"HOME", buffer, buffer_len);
+ break;
+ case 2:
+ /* HOMEDRIVE + HOMEPATH */
+ len = GetEnvironmentVariableW(L"HOMEDRIVE", buffer, buffer_len);
+ GetEnvironmentVariableW(L"HOMEPATH", buffer + len, buffer_len - len);
+ break;
+ case 3:
+ /* USERPROFILE */
+ GetEnvironmentVariableW(L"USERPROFILE", buffer, buffer_len);
+ break;
+ default:
+ break;
+ }
+
+ if (home_env) {
+ /* sanitize backslashes with forwardslashes */
+ replace_wchar(buffer, L'\\', L'/');
+
+ return buffer;
+ }
+
+ return NULL;
+}
+
+/* Remove trailing invalid ':$DATA' of the path. */
+static inline size_t
+remove_invalid_alternative_data(wchar_t *wfullpath, size_t size)
+{
+ static const wchar_t prime[] = L":$DATA";
+ enum { prime_len = (sizeof(prime) / sizeof(wchar_t)) -1 };
+
+ if (size <= prime_len || _wcsnicmp(wfullpath + size - prime_len, prime, prime_len) != 0)
+ return size;
+
+ /* alias of stream */
+ /* get rid of a bug of x64 VC++ */
+ if (wfullpath[size - (prime_len + 1)] == ':') {
+ /* remove trailing '::$DATA' */
+ size -= prime_len + 1; /* prime */
+ wfullpath[size] = L'\0';
+ }
+ else {
+ /* remove trailing ':$DATA' of paths like '/aa:a:$DATA' */
+ wchar_t *pos = wfullpath + size - (prime_len + 1);
+ while (!IS_DIR_SEPARATOR_P(*pos) && pos != wfullpath) {
+ if (*pos == L':') {
+ size -= prime_len; /* alternative */
+ wfullpath[size] = L'\0';
+ break;
+ }
+ pos--;
+ }
+ }
+ return size;
+}
+
+/* Return system code page. */
+static inline UINT
+system_code_page(void)
+{
+ return AreFileApisANSI() ? CP_ACP : CP_OEMCP;
+}
+
+/*
+ Return code page number of the encoding.
+ Cache code page into a hash for performance since finding the code page in
+ Encoding#names is slow.
+*/
+static UINT
+code_page(rb_encoding *enc)
+{
+ VALUE code_page_value, name_key;
+ VALUE encoding, names_ary = Qundef, name;
+ char *enc_name;
+ struct RString fake_str;
+ ID names;
+ long i;
+
+ if (!enc)
+ return system_code_page();
+
+ enc_name = (char *)rb_enc_name(enc);
+
+ fake_str.basic.flags = T_STRING|RSTRING_NOEMBED;
+ fake_str.basic.klass = rb_cString;
+ fake_str.as.heap.len = strlen(enc_name);
+ fake_str.as.heap.ptr = enc_name;
+ fake_str.as.heap.aux.capa = fake_str.as.heap.len;
+ name_key = (VALUE)&fake_str;
+ ENCODING_CODERANGE_SET(name_key, rb_usascii_encindex(), ENC_CODERANGE_7BIT);
+
+ code_page_value = rb_hash_lookup(rb_code_page, name_key);
+ if (code_page_value != Qnil)
+ return (UINT)FIX2INT(code_page_value);
+
+ name_key = rb_usascii_str_new2(enc_name);
+
+ encoding = rb_enc_from_encoding(enc);
+ if (!NIL_P(encoding)) {
+ CONST_ID(names, "names");
+ names_ary = rb_funcall(encoding, names, 0);
+ }
+
+ /* map US-ASCII and ASCII-8bit as code page 20127 (us-ascii) */
+ if (enc == rb_usascii_encoding() || enc == rb_ascii8bit_encoding()) {
+ UINT code_page = 20127;
+ rb_hash_aset(rb_code_page, name_key, INT2FIX(code_page));
+ return code_page;
+ }
+
+ if (names_ary != Qundef) {
+ for (i = 0; i < RARRAY_LEN(names_ary); i++) {
+ name = RARRAY_PTR(names_ary)[i];
+ if (strncmp("CP", RSTRING_PTR(name), 2) == 0) {
+ int code_page = atoi(RSTRING_PTR(name) + 2);
+ if (code_page != 0) {
+ rb_hash_aset(rb_code_page, name_key, INT2FIX(code_page));
+ return (UINT)code_page;
+ }
+ }
+ }
+ }
+
+ rb_hash_aset(rb_code_page, name_key, INT2FIX(INVALID_CODE_PAGE));
+ return INVALID_CODE_PAGE;
+}
+
+static inline VALUE
+fix_string_encoding(VALUE str, rb_encoding *encoding)
+{
+ VALUE result, tmp;
+
+ tmp = rb_enc_str_new(RSTRING_PTR(str), RSTRING_LEN(str), encoding);
+ result = rb_str_encode(tmp, rb_enc_from_encoding(rb_utf8_encoding()), 0, Qnil);
+
+ return result;
+}
+
+/*
+ Replace the last part of the path to long name.
+ We try to avoid to call FindFirstFileW() since it takes long time.
+*/
+static inline size_t
+replace_to_long_name(wchar_t **wfullpath, size_t size, int heap)
+{
+ WIN32_FIND_DATAW find_data;
+ HANDLE find_handle;
+
+ /*
+ Skip long name conversion if the path is already long name.
+ Short name is 8.3 format.
+ http://en.wikipedia.org/wiki/8.3_filename
+ This check can be skipped for directory components that have file
+ extensions longer than 3 characters, or total lengths longer than
+ 12 characters.
+ http://msdn.microsoft.com/en-us/library/windows/desktop/aa364980(v=vs.85).aspx
+ */
+ size_t const max_short_name_size = 8 + 1 + 3;
+ size_t const max_extension_size = 3;
+ size_t path_len = 1, extension_len = 0;
+ wchar_t *pos = *wfullpath;
+
+ if (size == 3 && pos[1] == L':' && pos[2] == L'\\' && pos[3] == L'\0') {
+ /* root path doesn't need short name expansion */
+ return size;
+ }
+
+ /* skip long name conversion if path contains wildcard characters */
+ if (wcspbrk(pos, L"*?")) {
+ return size;
+ }
+
+ pos = *wfullpath + size - 1;
+ while (!IS_DIR_SEPARATOR_P(*pos) && pos != *wfullpath) {
+ if (!extension_len && *pos == L'.') {
+ extension_len = path_len - 1;
+ }
+ if (path_len > max_short_name_size || extension_len > max_extension_size) {
+ return size;
+ }
+ path_len++;
+ pos--;
+ }
+
+ find_handle = FindFirstFileW(*wfullpath, &find_data);
+ if (find_handle != INVALID_HANDLE_VALUE) {
+ size_t trail_pos = wcslen(*wfullpath);
+ size_t file_len = wcslen(find_data.cFileName);
+
+ FindClose(find_handle);
+ while (trail_pos > 0) {
+ if (IS_DIR_SEPARATOR_P((*wfullpath)[trail_pos]))
+ break;
+ trail_pos--;
+ }
+ size = trail_pos + 1 + file_len;
+ if ((size + 1) > sizeof(*wfullpath) / sizeof((*wfullpath)[0])) {
+ wchar_t *buf = (wchar_t *)xmalloc((size + 1) * sizeof(wchar_t));
+ wcsncpy(buf, *wfullpath, trail_pos + 1);
+ if (heap)
+ xfree(*wfullpath);
+ *wfullpath = buf;
+ }
+ wcsncpy(*wfullpath + trail_pos + 1, find_data.cFileName, file_len + 1);
+ }
+ return size;
+}
+
+static inline VALUE
+get_user_from_path(wchar_t **wpath, int offset, UINT cp, UINT path_cp, rb_encoding *path_encoding)
+{
+ VALUE result, tmp;
+ wchar_t *wuser = *wpath + offset;
+ wchar_t *pos = wuser;
+ char *user;
+ size_t size;
+
+ while (!IS_DIR_SEPARATOR_P(*pos) && *pos != '\0')
+ pos++;
+
+ *pos = '\0';
+ convert_wchar_to_mb(wuser, &user, &size, cp);
+
+ /* convert to VALUE and set the path encoding */
+ if (path_cp == INVALID_CODE_PAGE) {
+ tmp = rb_enc_str_new(user, size, rb_utf8_encoding());
+ result = rb_str_encode(tmp, rb_enc_from_encoding(path_encoding), 0, Qnil);
+ rb_str_resize(tmp, 0);
+ }
+ else {
+ result = rb_enc_str_new(user, size, path_encoding);
+ }
+
+ if (user)
+ xfree(user);
+
+ return result;
+}
+
+VALUE
+rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_name, VALUE result)
+{
+ size_t size = 0, wpath_len = 0, wdir_len = 0, whome_len = 0;
+ size_t buffer_len = 0;
+ char *fullpath = NULL;
+ wchar_t *wfullpath = NULL, *wpath = NULL, *wpath_pos = NULL;
+ wchar_t *wdir = NULL, *wdir_pos = NULL;
+ wchar_t *whome = NULL, *buffer = NULL, *buffer_pos = NULL;
+ UINT path_cp, cp;
+ VALUE path = fname, dir = dname;
+ wchar_t wfullpath_buffer[PATH_BUFFER_SIZE];
+ wchar_t path_drive = L'\0', dir_drive = L'\0';
+ int ignore_dir = 0;
+ rb_encoding *path_encoding;
+ int tainted = 0;
+
+ /* tainted if path is tainted */
+ tainted = OBJ_TAINTED(path);
+
+ /* get path encoding */
+ if (NIL_P(dir)) {
+ path_encoding = rb_enc_get(path);
+ }
+ else {
+ path_encoding = rb_enc_check(path, dir);
+ }
+
+ cp = path_cp = code_page(path_encoding);
+
+ /* workaround invalid codepage */
+ if (path_cp == INVALID_CODE_PAGE) {
+ cp = CP_UTF8;
+ if (!NIL_P(path)) {
+ path = fix_string_encoding(path, path_encoding);
+ }
+ }
+
+ /* convert char * to wchar_t */
+ convert_mb_to_wchar(path, &wpath, &wpath_pos, &wpath_len, cp);
+
+ /* determine if we need the user's home directory */
+ /* expand '~' only if NOT rb_file_absolute_path() where `abs_mode` is 1 */
+ if (abs_mode == 0 && wpath_len > 0 && wpath_pos[0] == L'~' &&
+ (wpath_len == 1 || IS_DIR_SEPARATOR_P(wpath_pos[1]))) {
+ /* tainted if expanding '~' */
+ tainted = 1;
+
+ whome = home_dir();
+ if (whome == NULL) {
+ xfree(wpath);
+ rb_raise(rb_eArgError, "couldn't find HOME environment -- expanding `~'");
+ }
+ whome_len = wcslen(whome);
+
+ if (PathIsRelativeW(whome) && !(whome_len >= 2 && IS_DIR_UNC_P(whome))) {
+ xfree(wpath);
+ rb_raise(rb_eArgError, "non-absolute home");
+ }
+
+ /* use filesystem encoding if expanding home dir */
+ path_encoding = rb_filesystem_encoding();
+ cp = path_cp = system_code_page();
+
+ /* ignores dir since we are expading home */
+ ignore_dir = 1;
+
+ /* exclude ~ from the result */
+ wpath_pos++;
+ wpath_len--;
+
+ /* exclude separator if present */
+ if (wpath_len && IS_DIR_SEPARATOR_P(wpath_pos[0])) {
+ wpath_pos++;
+ wpath_len--;
+ }
+ }
+ else if (wpath_len >= 2 && wpath_pos[1] == L':') {
+ if (wpath_len >= 3 && IS_DIR_SEPARATOR_P(wpath_pos[2])) {
+ /* ignore dir since path contains a drive letter and a root slash */
+ ignore_dir = 1;
+ }
+ else {
+ /* determine if we ignore dir or not later */
+ path_drive = wpath_pos[0];
+ }
+ }
+ else if (abs_mode == 0 && wpath_len >= 2 && wpath_pos[0] == L'~') {
+ result = get_user_from_path(&wpath_pos, 1, cp, path_cp, path_encoding);
+
+ if (wpath)
+ xfree(wpath);
+
+ rb_raise(rb_eArgError, "can't find user %s", StringValuePtr(result));
+ }
+
+ /* convert dir */
+ if (!ignore_dir && !NIL_P(dir)) {
+ /* fix string encoding */
+ if (path_cp == INVALID_CODE_PAGE) {
+ dir = fix_string_encoding(dir, path_encoding);
+ }
+
+ /* convert char * to wchar_t */
+ convert_mb_to_wchar(dir, &wdir, &wdir_pos, &wdir_len, cp);
+
+ if (abs_mode == 0 && wdir_len > 0 && wdir_pos[0] == L'~' &&
+ (wdir_len == 1 || IS_DIR_SEPARATOR_P(wdir_pos[1]))) {
+ /* tainted if expanding '~' */
+ tainted = 1;
+
+ whome = home_dir();
+ if (whome == NULL) {
+ xfree(wpath);
+ xfree(wdir);
+ rb_raise(rb_eArgError, "couldn't find HOME environment -- expanding `~'");
+ }
+ whome_len = wcslen(whome);
+
+ if (PathIsRelativeW(whome) && !(whome_len >= 2 && IS_DIR_UNC_P(whome))) {
+ xfree(wpath);
+ xfree(wdir);
+ rb_raise(rb_eArgError, "non-absolute home");
+ }
+
+ /* exclude ~ from the result */
+ wdir_pos++;
+ wdir_len--;
+
+ /* exclude separator if present */
+ if (wdir_len && IS_DIR_SEPARATOR_P(wdir_pos[0])) {
+ wdir_pos++;
+ wdir_len--;
+ }
+ }
+ else if (wdir_len >= 2 && wdir[1] == L':') {
+ dir_drive = wdir[0];
+ if (wpath_len && IS_DIR_SEPARATOR_P(wpath_pos[0])) {
+ wdir_len = 2;
+ }
+ }
+ else if (wdir_len >= 2 && IS_DIR_UNC_P(wdir)) {
+ /* UNC path */
+ if (wpath_len && IS_DIR_SEPARATOR_P(wpath_pos[0])) {
+ /* cut the UNC path tail to '//host/share' */
+ size_t separators = 0;
+ size_t pos = 2;
+ while (pos < wdir_len && separators < 2) {
+ if (IS_DIR_SEPARATOR_P(wdir[pos])) {
+ separators++;
+ }
+ pos++;
+ }
+ if (separators == 2)
+ wdir_len = pos - 1;
+ }
+ }
+ else if (abs_mode == 0 && wdir_len >= 2 && wdir_pos[0] == L'~') {
+ result = get_user_from_path(&wdir_pos, 1, cp, path_cp, path_encoding);
+ if (wpath)
+ xfree(wpath);
+
+ if (wdir)
+ xfree(wdir);
+
+ rb_raise(rb_eArgError, "can't find user %s", StringValuePtr(result));
+ }
+ }
+
+ /* determine if we ignore dir or not */
+ if (!ignore_dir && path_drive && dir_drive) {
+ if (towupper(path_drive) == towupper(dir_drive)) {
+ /* exclude path drive letter to use dir */
+ wpath_pos += 2;
+ wpath_len -= 2;
+ }
+ else {
+ /* ignore dir since path drive is different from dir drive */
+ ignore_dir = 1;
+ wdir_len = 0;
+ }
+ }
+
+ if (!ignore_dir && wpath_len >= 2 && IS_DIR_UNC_P(wpath)) {
+ /* ignore dir since path has UNC root */
+ ignore_dir = 1;
+ wdir_len = 0;
+ }
+ else if (!ignore_dir && wpath_len >= 1 && IS_DIR_SEPARATOR_P(wpath[0]) &&
+ !dir_drive && !(wdir_len >= 2 && IS_DIR_UNC_P(wdir))) {
+ /* ignore dir since path has root slash and dir doesn't have drive or UNC root */
+ ignore_dir = 1;
+ wdir_len = 0;
+ }
+
+ buffer_len = wpath_len + 1 + wdir_len + 1 + whome_len + 1;
+
+ buffer = buffer_pos = (wchar_t *)xmalloc((buffer_len + 1) * sizeof(wchar_t));
+
+ /* add home */
+ if (whome_len) {
+ wcsncpy(buffer_pos, whome, whome_len);
+ buffer_pos += whome_len;
+ }
+
+ /* Add separator if required */
+ if (whome_len && wcsrchr(L"\\/:", buffer_pos[-1]) == NULL) {
+ buffer_pos[0] = L'\\';
+ buffer_pos++;
+ }
+
+ if (wdir_len) {
+ /* tainted if dir is used and dir is tainted */
+ if (!tainted && OBJ_TAINTED(dir))
+ tainted = 1;
+
+ wcsncpy(buffer_pos, wdir_pos, wdir_len);
+ buffer_pos += wdir_len;
+ }
+
+ /* add separator if required */
+ if (wdir_len && wcsrchr(L"\\/:", buffer_pos[-1]) == NULL) {
+ buffer_pos[0] = L'\\';
+ buffer_pos++;
+ }
+
+ /* now deal with path */
+ if (wpath_len) {
+ wcsncpy(buffer_pos, wpath_pos, wpath_len);
+ buffer_pos += wpath_len;
+ }
+
+ /* GetFullPathNameW requires at least "." to determine current directory */
+ if (wpath_len == 0) {
+ buffer_pos[0] = L'.';
+ buffer_pos++;
+ }
+
+ /* Ensure buffer is NULL terminated */
+ buffer_pos[0] = L'\0';
+
+ /* tainted if path is relative */
+ if (!tainted && PathIsRelativeW(buffer) && !(buffer_len >= 2 && IS_DIR_UNC_P(buffer)))
+ tainted = 1;
+
+ /* FIXME: Make this more robust */
+ /* Determine require buffer size */
+ size = GetFullPathNameW(buffer, PATH_BUFFER_SIZE, wfullpath_buffer, NULL);
+ if (size > PATH_BUFFER_SIZE) {
+ /* allocate more memory than alloted originally by PATH_BUFFER_SIZE */
+ wfullpath = (wchar_t *)xmalloc(size * sizeof(wchar_t));
+ size = GetFullPathNameW(buffer, size, wfullpath, NULL);
+ }
+ else {
+ wfullpath = wfullpath_buffer;
+ }
+
+ /* Remove any trailing slashes */
+ if (IS_DIR_SEPARATOR_P(wfullpath[size - 1]) &&
+ wfullpath[size - 2] != L':' &&
+ !(size == 2 && IS_DIR_UNC_P(wfullpath))) {
+ size -= 1;
+ wfullpath[size] = L'\0';
+ }
+
+ /* Remove any trailing dot */
+ if (wfullpath[size - 1] == L'.') {
+ size -= 1;
+ wfullpath[size] = L'\0';
+ }
+
+ /* removes trailing invalid ':$DATA' */
+ size = remove_invalid_alternative_data(wfullpath, size);
+
+ /* Replace the trailing path to long name */
+ if (long_name)
+ size = replace_to_long_name(&wfullpath, size, (wfullpath != wfullpath_buffer));
+
+ /* sanitize backslashes with forwardslashes */
+ replace_wchar(wfullpath, L'\\', L'/');
+
+ /* convert to char * */
+ size = WideCharToMultiByte(cp, 0, wfullpath, size, NULL, 0, NULL, NULL);
+ if (size > (size_t)RSTRING_LEN(result)) {
+ rb_str_modify(result);
+ rb_str_resize(result, size);
+ }
+
+ WideCharToMultiByte(cp, 0, wfullpath, size, RSTRING_PTR(result), size, NULL, NULL);
+ rb_str_set_len(result, size);
+
+ /* convert to VALUE and set the path encoding */
+ if (path_cp == INVALID_CODE_PAGE) {
+ VALUE tmp;
+ size_t len;
+
+ rb_enc_associate(result, rb_utf8_encoding());
+ ENC_CODERANGE_CLEAR(result);
+ tmp = rb_str_encode(result, rb_enc_from_encoding(path_encoding), 0, Qnil);
+ len = RSTRING_LEN(tmp);
+ rb_str_modify(result);
+ rb_str_resize(result, len);
+ memcpy(RSTRING_PTR(result), RSTRING_PTR(tmp), len);
+ rb_str_resize(tmp, 0);
+ }
+ rb_enc_associate(result, path_encoding);
+ ENC_CODERANGE_CLEAR(result);
+
+ /* makes the result object tainted if expanding tainted strings or returning modified path */
+ if (tainted)
+ OBJ_TAINT(result);
+
+ /* TODO: better cleanup */
+ if (buffer)
+ xfree(buffer);
+
+ if (wpath)
+ xfree(wpath);
+
+ if (wdir)
+ xfree(wdir);
+
+ if (whome)
+ xfree(whome);
+
+ if (wfullpath && wfullpath != wfullpath_buffer)
+ xfree(wfullpath);
+
+ if (fullpath)
+ xfree(fullpath);
+
+ return result;
+}
+
+int
+rb_file_load_ok(const char *path)
+{
+ int ret = 1;
+ DWORD attr = GetFileAttributes(path);
+ if (attr == INVALID_FILE_ATTRIBUTES ||
+ attr & FILE_ATTRIBUTE_DIRECTORY) {
+ ret = 0;
+ }
+ else {
+ HANDLE h = CreateFile(path, GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (h != INVALID_HANDLE_VALUE) {
+ CloseHandle(h);
+ }
+ else {
+ ret = 0;
+ }
+ }
+ return ret;
+}
+
+void
+rb_w32_init_file(void)
+{
+ rb_code_page = rb_hash_new();
+
+ /* prevent GC removing rb_code_page */
+ rb_gc_register_mark_object(rb_code_page);
+}
diff --git a/win32/makedirs.bat b/win32/makedirs.bat
new file mode 100755
index 0000000..13740d8
--- /dev/null
+++ b/win32/makedirs.bat
@@ -0,0 +1,3 @@
+@echo off
+setlocal EnableExtensions
+for %%I in (%*) do if not exist "%%~I/." mkdir "%%~I"
diff --git a/win32/mkexports.rb b/win32/mkexports.rb
index 9b45051..cc3dcf2 100755
--- a/win32/mkexports.rb
+++ b/win32/mkexports.rb
@@ -111,8 +111,8 @@ class Exports::Mswin < Exports
next unless l.sub!(/.*?\s(\(\)\s+)?External\s+\|\s+/, '')
is_data = !$1
if noprefix or /^[@_]/ =~ l
- next if /(?!^)@.*@/ =~ l || /@[[:xdigit:]]{8,16}$/ =~ l ||
- /^_(?:Init_|.*_threadptr_|DllMain@)/ =~ l
+ next if /(?!^)@.*@/ =~ l || /@[[:xdigit:]]{8,32}$/ =~ l ||
+ /^_?(?:Init_|.*_threadptr_|DllMain\b)/ =~ l
l.sub!(/^[@_]/, '') if /@\d+$/ !~ l
elsif !l.sub!(/^(\S+) \([^@?\`\']*\)$/, '\1')
next
@@ -146,7 +146,7 @@ class Exports::Cygwin < Exports
def each_export(objs)
symprefix = RbConfig::CONFIG["SYMBOL_PREFIX"]
symprefix.strip! if symprefix
- re = /\s(?:(T)|[[:upper:]])\s#{symprefix}((?!Init_|.*_threadptr_|DllMain@).*)$/
+ re = /\s(?:(T)|[[:upper:]])\s#{symprefix}((?!Init_|.*_threadptr_|DllMain\b).*)$/
objdump(objs) do |l|
next if /@.*@/ =~ l
yield $2, !$1 if re =~ l
diff --git a/win32/rmall.bat b/win32/rmall.bat
index f49a168..f49a168 100644..100755
--- a/win32/rmall.bat
+++ b/win32/rmall.bat
diff --git a/win32/win32.c b/win32/win32.c
index 6ea6888..fbf3566 100644
--- a/win32/win32.c
+++ b/win32/win32.c
@@ -578,12 +578,6 @@ init_env(void)
typedef BOOL (WINAPI *cancel_io_t)(HANDLE);
static cancel_io_t cancel_io = NULL;
-int
-rb_w32_has_cancel_io(void)
-{
- return cancel_io != NULL;
-}
-
static void
init_func(void)
{
@@ -674,6 +668,8 @@ rb_w32_sysinit(int *argc, char ***argv)
_set_invalid_parameter_handler(invalid_parameter);
_RTC_SetErrorFunc(rtc_error_handler);
set_pioinfo_extra();
+#else
+ SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOGPFAULTERRORBOX);
#endif
get_version();
@@ -1379,6 +1375,7 @@ has_redirection(const char *cmd)
case '>':
case '<':
case '|':
+ case '&':
case '\n':
if (!quote)
return TRUE;
@@ -2086,6 +2083,15 @@ set_pioinfo_extra(void)
#define FDEV 0x40 /* file handle refers to device */
#define FTEXT 0x80 /* file handle is in text mode */
+static int is_socket(SOCKET);
+static int is_console(SOCKET);
+
+int
+rb_w32_io_cancelable_p(int fd)
+{
+ return cancel_io != NULL && (is_socket(TO_SOCKET(fd)) || !is_console(TO_SOCKET(fd)));
+}
+
static int
rb_w32_open_osfhandle(intptr_t osfhandle, int flags)
{
@@ -2316,25 +2322,10 @@ ioctl(int i, int u, ...)
return -1;
}
-#undef FD_SET
-
void
rb_w32_fdset(int fd, fd_set *set)
{
- unsigned int i;
- SOCKET s = TO_SOCKET(fd);
-
- for (i = 0; i < set->fd_count; i++) {
- if (set->fd_array[i] == s) {
- return;
- }
- }
- if (i == set->fd_count) {
- if (set->fd_count < FD_SETSIZE) {
- set->fd_array[i] = s;
- set->fd_count++;
- }
- }
+ FD_SET(fd, set);
}
#undef FD_CLR
@@ -2718,14 +2709,19 @@ rb_w32_select_with_thread(int nfds, fd_set *rd, fd_set *wr, fd_set *ex,
fd_set orig_rd;
fd_set orig_wr;
fd_set orig_ex;
- if (rd) orig_rd = *rd;
- if (wr) orig_wr = *wr;
- if (ex) orig_ex = *ex;
+
+ FD_ZERO(&orig_rd);
+ FD_ZERO(&orig_wr);
+ FD_ZERO(&orig_ex);
+
+ if (rd) copy_fd(&orig_rd, rd);
+ if (wr) copy_fd(&orig_wr, wr);
+ if (ex) copy_fd(&orig_ex, ex);
r = do_select(nfds, rd, wr, ex, &zero); // polling
if (r != 0) break; // signaled or error
- if (rd) *rd = orig_rd;
- if (wr) *wr = orig_wr;
- if (ex) *ex = orig_ex;
+ if (rd) copy_fd(rd, &orig_rd);
+ if (wr) copy_fd(wr, &orig_wr);
+ if (ex) copy_fd(ex, &orig_ex);
if (timeout) {
struct timeval now;
@@ -4131,7 +4127,8 @@ isUNCRoot(const WCHAR *path)
(dest).st_ctime = (src).st_ctime; \
} while (0)
-#ifdef __BORLANDC__
+static time_t filetime_to_unixtime(const FILETIME *ft);
+
#undef fstat
int
rb_w32_fstat(int fd, struct stat *st)
@@ -4140,10 +4137,18 @@ rb_w32_fstat(int fd, struct stat *st)
int ret = fstat(fd, st);
if (ret) return ret;
+#ifdef __BORLANDC__
st->st_mode &= ~(S_IWGRP | S_IWOTH);
- if (GetFileInformationByHandle((HANDLE)_get_osfhandle(fd), &info) &&
- !(info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) {
- st->st_mode |= S_IWUSR;
+#endif
+ if (GetFileInformationByHandle((HANDLE)_get_osfhandle(fd), &info)) {
+#ifdef __BORLANDC__
+ if (!(info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) {
+ st->st_mode |= S_IWUSR;
+ }
+#endif
+ st->st_atime = filetime_to_unixtime(&info.ftLastAccessTime);
+ st->st_mtime = filetime_to_unixtime(&info.ftLastWriteTime);
+ st->st_ctime = filetime_to_unixtime(&info.ftCreationTime);
}
return ret;
}
@@ -4156,17 +4161,23 @@ rb_w32_fstati64(int fd, struct stati64 *st)
int ret = fstat(fd, &tmp);
if (ret) return ret;
+#ifdef __BORLANDC__
tmp.st_mode &= ~(S_IWGRP | S_IWOTH);
+#endif
COPY_STAT(tmp, *st, +);
if (GetFileInformationByHandle((HANDLE)_get_osfhandle(fd), &info)) {
+#ifdef __BORLANDC__
if (!(info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) {
st->st_mode |= S_IWUSR;
}
+#endif
st->st_size = ((__int64)info.nFileSizeHigh << 32) | info.nFileSizeLow;
+ st->st_atime = filetime_to_unixtime(&info.ftLastAccessTime);
+ st->st_mtime = filetime_to_unixtime(&info.ftLastWriteTime);
+ st->st_ctime = filetime_to_unixtime(&info.ftCreationTime);
}
return ret;
}
-#endif
static time_t
filetime_to_unixtime(const FILETIME *ft)
@@ -4224,7 +4235,14 @@ static int
check_valid_dir(const WCHAR *path)
{
WIN32_FIND_DATAW fd;
- HANDLE fh = open_dir_handle(path, &fd);
+ HANDLE fh;
+
+ /* GetFileAttributes() determines "..." as directory. */
+ /* We recheck it by FindFirstFile(). */
+ if (wcsstr(path, L"...") == NULL)
+ return 0;
+
+ fh = open_dir_handle(path, &fd);
if (fh == INVALID_HANDLE_VALUE)
return -1;
FindClose(fh);
@@ -4236,6 +4254,7 @@ winnt_stat(const WCHAR *path, struct stati64 *st)
{
HANDLE h;
WIN32_FIND_DATAW wfd;
+ WIN32_FILE_ATTRIBUTE_DATA wfa;
memset(st, 0, sizeof(*st));
st->st_nlink = 1;
@@ -4244,27 +4263,43 @@ winnt_stat(const WCHAR *path, struct stati64 *st)
errno = ENOENT;
return -1;
}
- h = FindFirstFileW(path, &wfd);
- if (h != INVALID_HANDLE_VALUE) {
- FindClose(h);
- st->st_mode = fileattr_to_unixmode(wfd.dwFileAttributes, path);
- st->st_atime = filetime_to_unixtime(&wfd.ftLastAccessTime);
- st->st_mtime = filetime_to_unixtime(&wfd.ftLastWriteTime);
- st->st_ctime = filetime_to_unixtime(&wfd.ftCreationTime);
- st->st_size = ((__int64)wfd.nFileSizeHigh << 32) | wfd.nFileSizeLow;
+ if (GetFileAttributesExW(path, GetFileExInfoStandard, (void*)&wfa)) {
+ if (wfa.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+ if (check_valid_dir(path)) return -1;
+ st->st_size = 0;
+ }
+ else {
+ st->st_size = ((__int64)wfa.nFileSizeHigh << 32) | wfa.nFileSizeLow;
+ }
+ st->st_mode = fileattr_to_unixmode(wfa.dwFileAttributes, path);
+ st->st_atime = filetime_to_unixtime(&wfa.ftLastAccessTime);
+ st->st_mtime = filetime_to_unixtime(&wfa.ftLastWriteTime);
+ st->st_ctime = filetime_to_unixtime(&wfa.ftCreationTime);
}
else {
- // If runtime stat(2) is called for network shares, it fails on WinNT.
- // Because GetDriveType returns 1 for network shares. (Win98 returns 4)
- DWORD attr = GetFileAttributesW(path);
- if (attr == (DWORD)-1L) {
- errno = map_errno(GetLastError());
+ /* GetFileAttributesEx failed; check why. */
+ int e = GetLastError();
+
+ if ((e == ERROR_FILE_NOT_FOUND) || (e == ERROR_INVALID_NAME)
+ || (e == ERROR_PATH_NOT_FOUND || (e == ERROR_BAD_NETPATH))) {
+ errno = map_errno(e);
return -1;
}
- if (attr & FILE_ATTRIBUTE_DIRECTORY) {
- if (check_valid_dir(path)) return -1;
+
+ /* Fall back to FindFirstFile for ERROR_SHARING_VIOLATION */
+ h = FindFirstFileW(path, &wfd);
+ if (h != INVALID_HANDLE_VALUE) {
+ FindClose(h);
+ st->st_mode = fileattr_to_unixmode(wfd.dwFileAttributes, path);
+ st->st_atime = filetime_to_unixtime(&wfd.ftLastAccessTime);
+ st->st_mtime = filetime_to_unixtime(&wfd.ftLastWriteTime);
+ st->st_ctime = filetime_to_unixtime(&wfd.ftCreationTime);
+ st->st_size = ((__int64)wfd.nFileSizeHigh << 32) | wfd.nFileSizeLow;
+ }
+ else {
+ errno = map_errno(GetLastError());
+ return -1;
}
- st->st_mode = fileattr_to_unixmode(attr, path);
}
st->st_dev = st->st_rdev = (iswalpha(path[0]) && path[1] == L':') ?
@@ -5145,6 +5180,49 @@ rb_w32_close(int fd)
return 0;
}
+static int
+setup_overlapped(OVERLAPPED *ol, int fd)
+{
+ memset(ol, 0, sizeof(*ol));
+ if (!(_osfile(fd) & (FDEV | FPIPE))) {
+ LONG high = 0;
+ DWORD method = _osfile(fd) & FAPPEND ? FILE_END : FILE_CURRENT;
+ DWORD low = SetFilePointer((HANDLE)_osfhnd(fd), 0, &high, method);
+#ifndef INVALID_SET_FILE_POINTER
+#define INVALID_SET_FILE_POINTER ((DWORD)-1)
+#endif
+ if (low == INVALID_SET_FILE_POINTER) {
+ DWORD err = GetLastError();
+ if (err != NO_ERROR) {
+ errno = map_errno(err);
+ return -1;
+ }
+ }
+ ol->Offset = low;
+ ol->OffsetHigh = high;
+ }
+ ol->hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
+ if (!ol->hEvent) {
+ errno = map_errno(GetLastError());
+ return -1;
+ }
+ return 0;
+}
+
+static void
+finish_overlapped(OVERLAPPED *ol, int fd, DWORD size)
+{
+ CloseHandle(ol->hEvent);
+
+ if (!(_osfile(fd) & (FDEV | FPIPE))) {
+ LONG high = ol->OffsetHigh;
+ DWORD low = ol->Offset + size;
+ if (low < ol->Offset)
+ ++high;
+ SetFilePointer((HANDLE)_osfhnd(fd), low, &high, FILE_BEGIN);
+ }
+}
+
#undef read
ssize_t
rb_w32_read(int fd, void *buf, size_t size)
@@ -5181,7 +5259,7 @@ rb_w32_read(int fd, void *buf, size_t size)
}
ret = 0;
- isconsole = is_console(_osfhnd(fd));
+ isconsole = is_console(_osfhnd(fd)) && (osver.dwMajorVersion < 6 || (osver.dwMajorVersion == 6 && osver.dwMinorVersion < 2));
if (isconsole) {
DWORD mode;
GetConsoleMode((HANDLE)_osfhnd(fd),&mode);
@@ -5203,25 +5281,7 @@ rb_w32_read(int fd, void *buf, size_t size)
/* if have cancel_io, use Overlapped I/O */
if (cancel_io) {
- memset(&ol, 0, sizeof(ol));
- if (!(_osfile(fd) & (FDEV | FPIPE))) {
- LONG high = 0;
- DWORD low = SetFilePointer((HANDLE)_osfhnd(fd), 0, &high,
- FILE_CURRENT);
-#ifndef INVALID_SET_FILE_POINTER
-#define INVALID_SET_FILE_POINTER ((DWORD)-1)
-#endif
- if (low == INVALID_SET_FILE_POINTER) {
- errno = map_errno(GetLastError());
- MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
- return -1;
- }
- ol.Offset = low;
- ol.OffsetHigh = high;
- }
- ol.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
- if (!ol.hEvent) {
- errno = map_errno(GetLastError());
+ if (setup_overlapped(&ol, fd)) {
MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
return -1;
}
@@ -5275,15 +5335,7 @@ rb_w32_read(int fd, void *buf, size_t size)
}
if (pol) {
- CloseHandle(ol.hEvent);
-
- if (!(_osfile(fd) & (FDEV | FPIPE))) {
- LONG high = ol.OffsetHigh;
- DWORD low = ol.Offset + read;
- if (low < ol.Offset)
- ++high;
- SetFilePointer((HANDLE)_osfhnd(fd), low, &high, FILE_BEGIN);
- }
+ finish_overlapped(&ol, fd, read);
}
ret += read;
@@ -5341,25 +5393,7 @@ rb_w32_write(int fd, const void *buf, size_t size)
/* if have cancel_io, use Overlapped I/O */
if (cancel_io) {
- memset(&ol, 0, sizeof(ol));
- if (!(_osfile(fd) & (FDEV | FPIPE))) {
- LONG high = 0;
- DWORD method = _osfile(fd) & FAPPEND ? FILE_END : FILE_CURRENT;
- DWORD low = SetFilePointer((HANDLE)_osfhnd(fd), 0, &high, method);
-#ifndef INVALID_SET_FILE_POINTER
-#define INVALID_SET_FILE_POINTER ((DWORD)-1)
-#endif
- if (low == INVALID_SET_FILE_POINTER) {
- errno = map_errno(GetLastError());
- MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
- return -1;
- }
- ol.Offset = low;
- ol.OffsetHigh = high;
- }
- ol.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
- if (!ol.hEvent) {
- errno = map_errno(GetLastError());
+ if (setup_overlapped(&ol, fd)) {
MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
return -1;
}
@@ -5405,15 +5439,7 @@ rb_w32_write(int fd, const void *buf, size_t size)
}
if (pol) {
- CloseHandle(ol.hEvent);
-
- if (!(_osfile(fd) & (FDEV | FPIPE))) {
- LONG high = ol.OffsetHigh;
- DWORD low = ol.Offset + written;
- if (low < ol.Offset)
- ++high;
- SetFilePointer((HANDLE)_osfhnd(fd), low, &high, FILE_BEGIN);
- }
+ finish_overlapped(&ol, fd, written);
}
ret += written;
@@ -5456,27 +5482,11 @@ rb_w32_write_console(uintptr_t strarg, int fd)
static int
unixtime_to_filetime(time_t time, FILETIME *ft)
{
- struct tm *tm;
- SYSTEMTIME st;
- FILETIME lt;
+ ULARGE_INTEGER tmp;
- tm = localtime(&time);
- if (!tm) {
- return -1;
- }
- st.wYear = tm->tm_year + 1900;
- st.wMonth = tm->tm_mon + 1;
- st.wDayOfWeek = tm->tm_wday;
- st.wDay = tm->tm_mday;
- st.wHour = tm->tm_hour;
- st.wMinute = tm->tm_min;
- st.wSecond = tm->tm_sec;
- st.wMilliseconds = 0;
- if (!SystemTimeToFileTime(&st, &lt) ||
- !LocalFileTimeToFileTime(&lt, ft)) {
- errno = map_errno(GetLastError());
- return -1;
- }
+ tmp.QuadPart = ((LONG_LONG)time + (LONG_LONG)((1970-1601)*365.2425) * 24 * 60 * 60) * 10 * 1000 * 1000;
+ ft->dwLowDateTime = tmp.LowPart;
+ ft->dwHighDateTime = tmp.HighPart;
return 0;
}