Created
March 17, 2012 09:57
-
-
Save shirosaki/2057234 to your computer and use it in GitHub Desktop.
fenix integraton
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/configure.in b/configure.in | |
index 9a679de..aad31de 100644 | |
--- a/configure.in | |
+++ b/configure.in | |
@@ -1055,7 +1055,7 @@ main() | |
AC_CHECK_FUNCS(cygwin_conv_path) | |
AC_LIBOBJ([langinfo]) | |
], | |
-[mingw*], [ LIBS="-lshell32 -lws2_32 -limagehlp $LIBS" | |
+[mingw*], [ LIBS="-lshell32 -lws2_32 -limagehlp -lshlwapi $LIBS" | |
ac_cv_header_a_out_h=no | |
ac_cv_header_pwd_h=no | |
ac_cv_header_utime_h=no | |
diff --git a/file.c b/file.c | |
index 4903295..772459a 100644 | |
--- a/file.c | |
+++ b/file.c | |
@@ -2889,8 +2889,9 @@ append_fspath(VALUE result, VALUE fname, char *dir, rb_encoding **enc, rb_encodi | |
return buf + dirlen; | |
} | |
-static VALUE | |
-file_expand_path(VALUE fname, VALUE dname, int abs_mode, VALUE result) | |
+#ifndef _WIN32 | |
+VALUE | |
+rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, VALUE result) | |
{ | |
const char *s, *b, *fend; | |
char *buf, *p, *pend, *root; | |
@@ -2952,7 +2953,7 @@ file_expand_path(VALUE fname, VALUE dname, int abs_mode, VALUE result) | |
/* specified drive, but not full path */ | |
int same = 0; | |
if (!NIL_P(dname) && !not_same_drive(dname, s[0])) { | |
- file_expand_path(dname, Qnil, abs_mode, result); | |
+ rb_file_expand_path_internal(dname, Qnil, abs_mode, result); | |
BUFINIT(); | |
if (has_drive_letter(p) && TOLOWER(p[0]) == TOLOWER(s[0])) { | |
/* ok, same drive */ | |
@@ -2976,7 +2977,7 @@ file_expand_path(VALUE fname, VALUE dname, int abs_mode, VALUE result) | |
#endif | |
else if (!rb_is_absolute_path(s)) { | |
if (!NIL_P(dname)) { | |
- file_expand_path(dname, Qnil, abs_mode, result); | |
+ rb_file_expand_path_internal(dname, Qnil, abs_mode, result); | |
rb_enc_associate(result, rb_enc_check(result, fname)); | |
BUFINIT(); | |
p = pend; | |
@@ -3229,6 +3230,7 @@ file_expand_path(VALUE fname, VALUE dname, int abs_mode, VALUE result) | |
ENC_CODERANGE_CLEAR(result); | |
return result; | |
} | |
+#endif | |
#define EXPAND_PATH_BUFFER() rb_usascii_str_new(0, MAXPATHLEN + 2) | |
@@ -3239,14 +3241,14 @@ file_expand_path(VALUE fname, VALUE dname, int abs_mode, VALUE result) | |
static VALUE | |
file_expand_path_1(VALUE fname) | |
{ | |
- return file_expand_path(fname, Qnil, 0, EXPAND_PATH_BUFFER()); | |
+ return rb_file_expand_path_internal(fname, Qnil, 0, EXPAND_PATH_BUFFER()); | |
} | |
VALUE | |
rb_file_expand_path(VALUE fname, VALUE dname) | |
{ | |
check_expand_path_args(fname, dname); | |
- return file_expand_path(fname, dname, 0, EXPAND_PATH_BUFFER()); | |
+ return rb_file_expand_path_internal(fname, dname, 0, EXPAND_PATH_BUFFER()); | |
} | |
/* | |
@@ -3283,7 +3285,7 @@ VALUE | |
rb_file_absolute_path(VALUE fname, VALUE dname) | |
{ | |
check_expand_path_args(fname, dname); | |
- return file_expand_path(fname, dname, 1, EXPAND_PATH_BUFFER()); | |
+ return rb_file_expand_path_internal(fname, dname, 1, EXPAND_PATH_BUFFER()); | |
} | |
/* | |
@@ -5243,7 +5245,7 @@ rb_find_file_ext_safe(VALUE *filep, const char *const *ext, int safe_level) | |
RB_GC_GUARD(str) = rb_get_path_check(str, safe_level); | |
if (RSTRING_LEN(str) == 0) continue; | |
- file_expand_path(fname, str, 0, tmp); | |
+ rb_file_expand_path_internal(fname, str, 0, tmp); | |
if (rb_file_load_ok(RSTRING_PTR(tmp))) { | |
*filep = copy_path_class(tmp, *filep); | |
return (int)(j+1); | |
@@ -5302,7 +5304,7 @@ rb_find_file_safe(VALUE path, int safe_level) | |
VALUE str = RARRAY_PTR(load_path)[i]; | |
RB_GC_GUARD(str) = rb_get_path_check(str, safe_level); | |
if (RSTRING_LEN(str) > 0) { | |
- file_expand_path(path, str, 0, tmp); | |
+ rb_file_expand_path_internal(path, str, 0, tmp); | |
f = RSTRING_PTR(tmp); | |
if (rb_file_load_ok(f)) goto found; | |
} | |
@@ -5537,4 +5539,8 @@ Init_File(void) | |
rb_define_method(rb_cStat, "setuid?", rb_stat_suid, 0); | |
rb_define_method(rb_cStat, "setgid?", rb_stat_sgid, 0); | |
rb_define_method(rb_cStat, "sticky?", rb_stat_sticky, 0); | |
+ | |
+#ifdef _WIN32 | |
+ rb_w32_init_file(); | |
+#endif | |
} | |
diff --git a/include/ruby/win32.h b/include/ruby/win32.h | |
index 807d388..a275fd5 100644 | |
--- a/include/ruby/win32.h | |
+++ b/include/ruby/win32.h | |
@@ -306,6 +306,7 @@ extern int rb_w32_ustati64(const char *, struct stati64 *); | |
extern int rb_w32_access(const char *, int); | |
extern int rb_w32_uaccess(const char *, int); | |
extern char rb_w32_fd_is_text(int); | |
+extern void rb_w32_init_file(); | |
#ifdef __BORLANDC__ | |
extern int rb_w32_fstati64(int, struct stati64 *); | |
diff --git a/internal.h b/internal.h | |
index e581842..4769226 100644 | |
--- a/internal.h | |
+++ b/internal.h | |
@@ -96,6 +96,7 @@ VALUE rb_home_dir(const char *user, VALUE result); | |
VALUE rb_realpath_internal(VALUE basedir, VALUE path, int strict); | |
void rb_file_const(const char*, VALUE); | |
int rb_file_load_ok(const char *); | |
+VALUE rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, VALUE result); | |
void Init_File(void); | |
/* gc.c */ | |
diff --git a/lib/webrick/httpservlet/filehandler.rb b/lib/webrick/httpservlet/filehandler.rb | |
index 8736f57..adae046 100644 | |
--- a/lib/webrick/httpservlet/filehandler.rb | |
+++ b/lib/webrick/httpservlet/filehandler.rb | |
@@ -327,12 +327,38 @@ module WEBrick | |
end | |
end | |
+ if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM | |
+ require 'dl/import' | |
+ require 'dl/types' | |
+ | |
+ module Kernel32 | |
+ extend DL::Importer | |
+ dlload "kernel32" | |
+ include DL::Win32Types | |
+ extern "DWORD GetLongPathName(LPCSTR, LPSTR, DWORD)" | |
+ | |
+ def self.long_path_name(name) | |
+ if (len = GetLongPathName(name, nil, 0)).nonzero? | |
+ buf = "\0" * len | |
+ buf[0...GetLongPathName(name, buf, buf.size)] | |
+ else | |
+ name | |
+ end | |
+ end | |
+ end | |
+ | |
+ def long_path_name(name) | |
+ Kernel32.long_path_name(name) | |
+ end | |
+ end | |
+ | |
def shift_path_info(req, res, path_info, base=nil) | |
tmp = path_info.shift | |
base = base || tmp | |
req.path_info = path_info.join | |
req.script_name << base | |
res.filename = File.expand_path(res.filename + base) | |
+ res.filename = long_path_name(res.filename) if defined?(long_path_name) | |
check_filename(req, res, File.basename(res.filename)) | |
end | |
diff --git a/test/ruby/test_file_exhaustive.rb b/test/ruby/test_file_exhaustive.rb | |
index a19fcd9..ead2838 100644 | |
--- a/test/ruby/test_file_exhaustive.rb | |
+++ b/test/ruby/test_file_exhaustive.rb | |
@@ -431,7 +431,13 @@ class TestFileExhaustive < Test::Unit::TestCase | |
begin | |
bug3630 = '[ruby-core:31537]' | |
home = ENV["HOME"] | |
+ home_drive = ENV["HOMEDRIVE"] | |
+ home_path = ENV["HOMEPATH"] | |
+ user_profile = ENV["USERPROFILE"] | |
ENV["HOME"] = nil | |
+ ENV["HOMEDRIVE"] = nil | |
+ ENV["HOMEPATH"] = nil | |
+ ENV["USERPROFILE"] = nil | |
assert_raise(ArgumentError) { File.expand_path("~") } | |
ENV["HOME"] = "~" | |
assert_raise(ArgumentError, bug3630) { File.expand_path("~") } | |
@@ -439,6 +445,9 @@ class TestFileExhaustive < Test::Unit::TestCase | |
assert_raise(ArgumentError, bug3630) { File.expand_path("~") } | |
ensure | |
ENV["HOME"] = home | |
+ ENV["HOMEDRIVE"] = home_drive | |
+ ENV["HOMEPATH"] = home_path | |
+ ENV["USERPROFILE"] = user_profile | |
end | |
assert_incompatible_encoding {|d| File.expand_path(d)} | |
end | |
diff --git a/win32/Makefile.sub b/win32/Makefile.sub | |
index df3ae39..951cd89 100644 | |
--- a/win32/Makefile.sub | |
+++ b/win32/Makefile.sub | |
@@ -223,7 +223,7 @@ 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) | |
diff --git a/win32/file.c b/win32/file.c | |
index 13325a3..a9f313e 100644 | |
--- a/win32/file.c | |
+++ b/win32/file.c | |
@@ -1,5 +1,15 @@ | |
#include "ruby/ruby.h" | |
+#include "ruby/encoding.h" | |
#include <winbase.h> | |
+#include <wchar.h> | |
+#include <shlwapi.h> | |
+ | |
+#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])) | |
+ | |
+#define malloc xmalloc | |
+#define free xfree | |
+ | |
int | |
rb_file_load_ok(const char *path) | |
@@ -23,3 +33,527 @@ rb_file_load_ok(const char *path) | |
} | |
return ret; | |
} | |
+ | |
+ | |
+static inline void | |
+replace_wchar(wchar_t *s, int find, int replace) | |
+{ | |
+ while (*s != 0) { | |
+ if (*s == find) | |
+ *s = replace; | |
+ s++; | |
+ } | |
+} | |
+ | |
+/* | |
+ * Return user's home directory using environment variables combinations. | |
+ * Memory allocated by this function should be manually freeded afterwards. | |
+ */ | |
+static wchar_t * | |
+home_dir() | |
+{ | |
+ wchar_t *buffer = NULL; | |
+ size_t buffer_len = 0, len = 0; | |
+ size_t home_env = 0; | |
+ | |
+ // determine User's home directory trying: | |
+ // HOME, HOMEDRIVE + HOMEPATH and USERPROFILE environment variables | |
+ // TODO: Special Folders - Profile and Personal | |
+ | |
+ /* | |
+ * 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 *)malloc(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: | |
+ // wprintf(L"Failed to determine user home directory.\n"); | |
+ break; | |
+ } | |
+ | |
+ if (home_env) { | |
+ // sanitize backslashes with forwardslashes | |
+ replace_wchar(buffer, L'\\', L'/'); | |
+ | |
+ // wprintf(L"home dir: '%s' using home_env (%i)\n", buffer, home_env); | |
+ return buffer; | |
+ } | |
+ | |
+ return NULL; | |
+} | |
+ | |
+ | |
+/* Convert the path from char to wchar with specified code page */ | |
+static inline void | |
+path_to_wchar(VALUE path, wchar_t **wpath, wchar_t **wpath_pos, size_t *wpath_len, UINT code_page) | |
+{ | |
+ size_t size; | |
+ | |
+ if (NIL_P(path)) | |
+ return; | |
+ | |
+ size = MultiByteToWideChar(code_page, 0, RSTRING_PTR(path), -1, NULL, 0) + 1; | |
+ *wpath = (wchar_t *)malloc(size * sizeof(wchar_t)); | |
+ if (wpath_pos) | |
+ *wpath_pos = *wpath; | |
+ | |
+ MultiByteToWideChar(code_page, 0, RSTRING_PTR(path), -1, *wpath, size); | |
+ *wpath_len = size - 2; // wcslen(*wpath); | |
+} | |
+ | |
+/* 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; | |
+ | |
+ // wprintf(L"remove trailng ':$DATA': %s, %s\n", wfullpath, &wfullpath[size - prime_len]); | |
+ /* 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'; | |
+ // wprintf(L"removed trailng '::$DATA': %s\n", wfullpath); | |
+ } 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'; | |
+ // wprintf(L"removed trailng ':$DATA': %s\n", wfullpath); | |
+ break; | |
+ } | |
+ pos--; | |
+ } | |
+ } | |
+ return size; | |
+} | |
+ | |
+/* Return system code page. */ | |
+static inline UINT | |
+system_code_page() { | |
+ return AreFileApisANSI() ? CP_ACP : CP_OEMCP; | |
+} | |
+ | |
+/* cache 'encoding name' => 'code page' into a hash */ | |
+static VALUE rb_code_page; | |
+ | |
+/* | |
+ * 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); | |
+ OBJ_FREEZE(name_key); | |
+ | |
+ code_page_value = rb_hash_lookup(rb_code_page, name_key); | |
+ if (code_page_value != Qnil) { | |
+ // printf("cached code page: %i\n", FIX2INT(code_page_value)); | |
+ if (FIX2INT(code_page_value) == -1) { | |
+ return system_code_page(); | |
+ } else { | |
+ 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); | |
+ } | |
+ | |
+ 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); | |
+ rb_hash_aset(rb_code_page, name_key, INT2FIX(code_page)); | |
+ return (UINT)code_page; | |
+ } | |
+ } | |
+ } | |
+ | |
+ rb_hash_aset(rb_code_page, name_key, INT2FIX(-1)); | |
+ return system_code_page(); | |
+} | |
+ | |
+#define PATH_BUFFER_SIZE MAX_PATH * 2 | |
+ | |
+// TODO: can we fail allocating memory? | |
+VALUE | |
+rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, VALUE result) | |
+{ | |
+ size_t size = 0, wpath_len = 0, wdir_len = 0, whome_len = 0; | |
+ size_t buffer_len = 0; | |
+ wchar_t *wfullpath = NULL, *wpath = NULL, *wpath_pos = NULL, *wdir = NULL; | |
+ wchar_t *whome = NULL, *buffer = NULL, *buffer_pos = NULL; | |
+ UINT 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 = code_page(path_encoding); | |
+ // printf("code page: %i\n", cp); | |
+ | |
+ // coerce them to string | |
+ // path = coerce_to_path(path); | |
+ | |
+ // convert char * to wchar_t | |
+ // path | |
+ path_to_wchar(path, &wpath, &wpath_pos, &wpath_len, cp); | |
+ // wprintf(L"wpath: '%s' with (%i) characters long.\n", wpath, wpath_len); | |
+ | |
+ /* determine if we need the user's home directory */ | |
+ /* execute only if NOT absolute_path(). `abs_mode` is 1 if absolute_path() */ | |
+ if (abs_mode == 0 && ((wpath_len == 1 && wpath_pos[0] == L'~') || | |
+ (wpath_len >= 2 && wpath_pos[0] == L'~' && IS_DIR_SEPARATOR_P(wpath_pos[1])))) { | |
+ /* tainted if expanding '~' */ | |
+ tainted = 1; | |
+ | |
+ // wprintf(L"wpath requires expansion.\n"); | |
+ whome = home_dir(); | |
+ if (whome == NULL) { | |
+ free(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))) { | |
+ free(wpath); | |
+ rb_raise(rb_eArgError, "non-absolute home"); | |
+ } | |
+ | |
+ // wprintf(L"whome: '%s' with (%i) characters long.\n", whome, whome_len); | |
+ | |
+ /* 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])) { | |
+ // wprintf(L"excluding expansion character and separator\n"); | |
+ 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 */ | |
+ // wprintf(L"Ignore dir since we have drive letter and root slash\n"); | |
+ 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'~') { | |
+ wchar_t *wuser = wpath_pos + 1; | |
+ wchar_t *pos = wuser; | |
+ char *user; | |
+ | |
+ /* tainted if expanding '~' */ | |
+ tainted = 1; | |
+ | |
+ while (!IS_DIR_SEPARATOR_P(*pos) && *pos != '\0') | |
+ pos++; | |
+ | |
+ *pos = '\0'; | |
+ size = WideCharToMultiByte(cp, 0, wuser, -1, NULL, 0, NULL, NULL); | |
+ user = (char *)malloc(size * sizeof(char)); | |
+ WideCharToMultiByte(cp, 0, wuser, -1, user, size, NULL, NULL); | |
+ | |
+ /* convert to VALUE and set the path encoding */ | |
+ result = rb_enc_str_new(user, size - 1, path_encoding); | |
+ | |
+ free(wpath); | |
+ if (user) | |
+ free(user); | |
+ | |
+ rb_raise(rb_eArgError, "can't find user %s", StringValuePtr(result)); | |
+ } | |
+ | |
+ /* convert dir */ | |
+ if (!ignore_dir && !NIL_P(dir)) { | |
+ // coerce them to string | |
+ // dir = coerce_to_path(dir); | |
+ | |
+ // convert char * to wchar_t | |
+ // dir | |
+ path_to_wchar(dir, &wdir, NULL, &wdir_len, cp); | |
+ // wprintf(L"wdir: '%s' with (%i) characters long.\n", wdir, wdir_len); | |
+ | |
+ 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; | |
+ // wprintf(L"UNC wdir: '%s' with (%i) characters.\n", wdir, wdir_len); | |
+ } | |
+ } | |
+ } | |
+ | |
+ /* 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 */ | |
+ // wprintf(L"excluding path drive letter\n"); | |
+ 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; | |
+ } | |
+ | |
+ // wprintf(L"wpath_len: %i\n", wpath_len); | |
+ // wprintf(L"wdir_len: %i\n", wdir_len); | |
+ // wprintf(L"whome_len: %i\n", whome_len); | |
+ | |
+ buffer_len = wpath_len + 1 + wdir_len + 1 + whome_len + 1; | |
+ // wprintf(L"buffer_len: %i\n", buffer_len + 1); | |
+ | |
+ buffer = buffer_pos = (wchar_t *)malloc((buffer_len + 1) * sizeof(wchar_t)); | |
+ | |
+ /* add home */ | |
+ if (whome_len) { | |
+ // wprintf(L"Copying whome...\n"); | |
+ wcsncpy(buffer_pos, whome, whome_len); | |
+ buffer_pos += whome_len; | |
+ } | |
+ | |
+ /* Add separator if required */ | |
+ if (whome_len && wcsrchr(L"\\/:", buffer_pos[-1]) == NULL) { | |
+ // wprintf(L"Adding separator after whome\n"); | |
+ 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; | |
+ | |
+ // wprintf(L"Copying wdir...\n"); | |
+ wcsncpy(buffer_pos, wdir, wdir_len); | |
+ buffer_pos += wdir_len; | |
+ } | |
+ | |
+ /* add separator if required */ | |
+ if (wdir_len && wcsrchr(L"\\/:", buffer_pos[-1]) == NULL) { | |
+ // wprintf(L"Adding separator after wdir\n"); | |
+ buffer_pos[0] = L'\\'; | |
+ buffer_pos++; | |
+ } | |
+ | |
+ /* now deal with path */ | |
+ if (wpath_len) { | |
+ // wprintf(L"Copying wpath...\n"); | |
+ wcsncpy(buffer_pos, wpath_pos, wpath_len); | |
+ buffer_pos += wpath_len; | |
+ } | |
+ | |
+ /* GetFullPathNameW requires at least "." to determine current directory */ | |
+ if (wpath_len == 0) { | |
+ // wprintf(L"Adding '.' to buffer\n"); | |
+ 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; | |
+ } | |
+ | |
+ // wprintf(L"buffer: '%s'\n", buffer); | |
+ | |
+ // FIXME: Make this more robust | |
+ // Determine require buffer size | |
+ size = GetFullPathNameW(buffer, PATH_BUFFER_SIZE, wfullpath_buffer, NULL); | |
+ if (size) { | |
+ if (size > PATH_BUFFER_SIZE) { | |
+ // allocate enough memory to contain the response | |
+ wfullpath = (wchar_t *)malloc(size * sizeof(wchar_t)); | |
+ size = GetFullPathNameW(buffer, size, wfullpath, NULL); | |
+ } else { | |
+ wfullpath = wfullpath_buffer; | |
+ } | |
+ // wprintf(L"wfullpath: '%s'\n", wfullpath); | |
+ | |
+ | |
+ /* Calculate the new size and leave the garbage out */ | |
+ // size = wcslen(wfullpath); | |
+ | |
+ /* Remove any trailing slashes */ | |
+ if (IS_DIR_SEPARATOR_P(wfullpath[size - 1]) && | |
+ wfullpath[size - 2] != L':' && | |
+ !(size == 2 && IS_DIR_UNC_P(wfullpath))) { | |
+ // wprintf(L"Removing trailing slash\n"); | |
+ size -= 1; | |
+ wfullpath[size] = L'\0'; | |
+ } | |
+ // wprintf(L"wfullpath: '%s'\n", wfullpath); | |
+ | |
+ /* Remove any trailing dot */ | |
+ if (wfullpath[size - 1] == L'.') { | |
+ // wprintf(L"Removing trailing dot\n"); | |
+ size -= 1; | |
+ wfullpath[size] = L'\0'; | |
+ } | |
+ | |
+ /* removes trailing invalid ':$DATA' */ | |
+ size = remove_invalid_alternative_data(wfullpath, size); | |
+ | |
+ // sanitize backslashes with forwardslashes | |
+ replace_wchar(wfullpath, L'\\', L'/'); | |
+ // wprintf(L"wfullpath: '%s'\n", wfullpath); | |
+ | |
+ // What CodePage should we use? | |
+ // cp = AreFileApisANSI() ? CP_ACP : CP_OEMCP; | |
+ | |
+ // convert to char * | |
+ size = WideCharToMultiByte(cp, 0, wfullpath, -1, NULL, 0, NULL, NULL); | |
+ // fullpath = (char *)malloc(size * sizeof(char)); | |
+ if (size > (size_t)RSTRING_LEN(result)) | |
+ rb_str_resize(result, size); | |
+ | |
+ WideCharToMultiByte(cp, 0, wfullpath, -1, RSTRING_PTR(result), size, NULL, NULL); | |
+ | |
+ /* set the String VALUE length and the path encoding */ | |
+ rb_str_set_len(result, size - 1); | |
+ rb_enc_associate(result, path_encoding); | |
+ | |
+ /* makes the result object tainted if expanding tainted strings or returning modified path */ | |
+ if (tainted) | |
+ OBJ_TAINT(result); | |
+ } | |
+ | |
+ // TODO: better cleanup | |
+ if (buffer) | |
+ free(buffer); | |
+ | |
+ if (wpath) | |
+ free(wpath); | |
+ | |
+ if (wdir) | |
+ free(wdir); | |
+ | |
+ if (whome) | |
+ free(whome); | |
+ | |
+ if (wfullpath && wfullpath != wfullpath_buffer) | |
+ free(wfullpath); | |
+ | |
+ return result; | |
+} | |
+ | |
+ | |
+void | |
+rb_w32_init_file() | |
+{ | |
+ rb_code_page = rb_hash_new(); | |
+ | |
+ /* prevent GC removing rb_code_page */ | |
+ rb_gc_register_mark_object(rb_code_page); | |
+} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
51) Failure: | |
test_generate_bin_bindir_with_user_install_warning(TestGemInstaller) [c:/Users/h | |
iroshi/work/ruby/test/rubygems/test_gem_installer.rb:226]: | |
--- expected | |
+++ actual | |
@@ -1 +1,3 @@ | |
-"" | |
+"WARNING: You don't have C:\\Windows in your PATH, | |
+\t gem executables will not run. | |
+" | |
52) Failure: | |
test_constants(OpenSSL::TestConfig) [c:/Users/hiroshi/work/ruby/test/openssl/tes | |
t_config.rb:20]: | |
Exception raised: | |
<#<Errno::ENOENT: No such file or directory - C:/projects/rubyinstaller-git/sand | |
box/openssl/ssl/openssl.cnf>>. | |
53) Failure: | |
test_s_open_error(TestGDBM) [c:/Users/hiroshi/work/ruby/test/gdbm/test_gdbm.rb:2 | |
27]: | |
[Errno::EACCES, Errno::EWOULDBLOCK] expected but nothing was raised. | |
54) Failure: | |
test_reorganize(TestGDBM) [c:/Users/hiroshi/work/ruby/test/gdbm/test_gdbm.rb:611 | |
]: | |
<true> expected but was | |
<false>. | |
10786 tests, 1913725 assertions, 4 failures, 0 errors, 78 skips | |
ruby -v: ruby 2.0.0dev (2012-03-17 trunk 35075) [i386-mingw32] | |
make: *** [yes-test-all] Error 4 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment