ruby-changes:50625
From: nagachika <ko1@a...>
Date: Sat, 17 Mar 2018 02:34:51 +0900 (JST)
Subject: [ruby-changes:50625] nagachika:r62784 (ruby_2_4): merge revision(s) 58745, 58780, 59040, 60743: [Backport #13863]
nagachika 2018-03-17 02:34:44 +0900 (Sat, 17 Mar 2018) New Revision: 62784 https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=62784 Log: merge revision(s) 58745,58780,59040,60743: [Backport #13863] rb_w32_ugetcwd: UTF-8 version getcwd * dir.c (rb_dir_getwd): convert from UTF-8. * win32/win32.c (w32_getcwd): codepage aware getcwd using GetCurrentDirectoryW. potential memory leak * dir.c (rb_dir_getwd): get rid of potential memory leak. * util.c (ruby_getcwd): ditto. file.c: realpath in OS path encoding * dir.c (rb_dir_getwd_ospath): return cwd path in the OS path encoding. * file.c (rb_realpath_internal): work in the OS path encoding load.c: cwd encoding * load.c (rb_get_expanded_load_path): save cwd cache in OS path encoding, to get rid of unnecessary conversion and infinite loading when it needs encoding conversion. [ruby-dev:50221] [Bug #13863] Modified directories: branches/ruby_2_4/ Modified files: branches/ruby_2_4/dir.c branches/ruby_2_4/file.c branches/ruby_2_4/internal.h branches/ruby_2_4/load.c branches/ruby_2_4/test/ruby/test_rubyoptions.rb branches/ruby_2_4/util.c branches/ruby_2_4/version.h branches/ruby_2_4/win32/dir.h branches/ruby_2_4/win32/win32.c Index: ruby_2_4/test/ruby/test_rubyoptions.rb =================================================================== --- ruby_2_4/test/ruby/test_rubyoptions.rb (revision 62783) +++ ruby_2_4/test/ruby/test_rubyoptions.rb (revision 62784) @@ -920,4 +920,16 @@ class TestRubyOptions < Test::Unit::Test https://github.com/ruby/ruby/blob/trunk/ruby_2_4/test/ruby/test_rubyoptions.rb#L920 end end end + + def test_cwd_encoding + with_tmpchdir do + testdir = "\u30c6\u30b9\u30c8" + Dir.mkdir(testdir) + Dir.chdir(testdir) do + File.write("a.rb", "require './b'") + File.write("b.rb", "puts 'ok'") + assert_ruby_status([{"RUBYLIB"=>"."}, *%w[-E cp932:utf-8 a.rb]]) + end + end + end end Index: ruby_2_4/file.c =================================================================== --- ruby_2_4/file.c (revision 62783) +++ ruby_2_4/file.c (revision 62784) @@ -126,6 +126,14 @@ int flock(int, int); https://github.com/ruby/ruby/blob/trunk/ruby_2_4/file.c#L126 #define STAT(p, s) stat((p), (s)) #endif +#if defined _WIN32 || defined __APPLE__ +# define USE_OSPATH 1 +# define TO_OSPATH(str) rb_str_encode_ospath(str) +#else +# define USE_OSPATH 0 +# define TO_OSPATH(str) (str) +#endif + VALUE rb_cFile; VALUE rb_mFileTest; VALUE rb_cStat; @@ -222,7 +230,7 @@ rb_get_path(VALUE obj) https://github.com/ruby/ruby/blob/trunk/ruby_2_4/file.c#L230 VALUE rb_str_encode_ospath(VALUE path) { -#if defined _WIN32 || defined __APPLE__ +#if USE_OSPATH int encidx = ENCODING_GET(path); #ifdef _WIN32 if (encidx == ENCINDEX_ASCII) { @@ -3833,11 +3841,10 @@ realpath_rec(long *prefixlenp, VALUE *re https://github.com/ruby/ruby/blob/trunk/ruby_2_4/file.c#L3841 else { struct stat sbuf; int ret; - VALUE testpath2 = rb_str_encode_ospath(testpath); #ifdef __native_client__ - ret = stat(RSTRING_PTR(testpath2), &sbuf); + ret = stat(RSTRING_PTR(testpath), &sbuf); #else - ret = lstat(RSTRING_PTR(testpath2), &sbuf); + ret = lstat(RSTRING_PTR(testpath), &sbuf); #endif if (ret == -1) { int e = errno; @@ -3909,9 +3916,12 @@ rb_check_realpath_internal(VALUE basedir https://github.com/ruby/ruby/blob/trunk/ruby_2_4/file.c#L3916 if (!NIL_P(basedir)) { FilePathValue(basedir); - basedir = rb_str_dup_frozen(basedir); + basedir = TO_OSPATH(rb_str_dup_frozen(basedir)); } + enc = rb_enc_get(unresolved_path); + origenc = enc; + unresolved_path = TO_OSPATH(unresolved_path); RSTRING_GETMEM(unresolved_path, ptr, len); path_names = skipprefixroot(ptr, ptr + len, rb_enc_get(unresolved_path)); if (ptr != path_names) { @@ -3928,7 +3938,7 @@ rb_check_realpath_internal(VALUE basedir https://github.com/ruby/ruby/blob/trunk/ruby_2_4/file.c#L3938 } } - curdir = rb_dir_getwd(); + curdir = rb_dir_getwd_ospath(); RSTRING_GETMEM(curdir, ptr, len); curdir_names = skipprefixroot(ptr, ptr + len, rb_enc_get(curdir)); resolved = rb_str_subseq(curdir, 0, curdir_names - ptr); @@ -3936,7 +3946,6 @@ rb_check_realpath_internal(VALUE basedir https://github.com/ruby/ruby/blob/trunk/ruby_2_4/file.c#L3946 root_found: RSTRING_GETMEM(resolved, prefixptr, prefixlen); pend = prefixptr + prefixlen; - enc = rb_enc_get(resolved); ptr = chompdirsep(prefixptr, pend, enc); if (ptr < pend) { prefixlen = ++ptr - prefixptr; @@ -3951,7 +3960,6 @@ rb_check_realpath_internal(VALUE basedir https://github.com/ruby/ruby/blob/trunk/ruby_2_4/file.c#L3960 } #endif - origenc = enc; switch (rb_enc_to_index(enc)) { case ENCINDEX_ASCII: case ENCINDEX_US_ASCII: @@ -3970,8 +3978,14 @@ rb_check_realpath_internal(VALUE basedir https://github.com/ruby/ruby/blob/trunk/ruby_2_4/file.c#L3978 if (realpath_rec(&prefixlen, &resolved, path_names, loopcheck, mode, 1)) return Qnil; - if (origenc != enc && rb_enc_str_asciionly_p(resolved)) - rb_enc_associate(resolved, origenc); + if (origenc != rb_enc_get(resolved)) { + if (rb_enc_str_asciionly_p(resolved)) { + rb_enc_associate(resolved, origenc); + } + else { + resolved = rb_str_conv_enc(resolved, NULL, origenc); + } + } OBJ_TAINT(resolved); return resolved; Index: ruby_2_4/load.c =================================================================== --- ruby_2_4/load.c (revision 62783) +++ ruby_2_4/load.c (revision 62784) @@ -95,15 +95,6 @@ rb_construct_expanded_load_path(enum exp https://github.com/ruby/ruby/blob/trunk/ruby_2_4/load.c#L95 rb_ary_replace(vm->load_path_snapshot, vm->load_path); } -static VALUE -load_path_getcwd(void) -{ - char *cwd = my_getcwd(); - VALUE cwd_str = rb_filesystem_str_new_cstr(cwd); - xfree(cwd); - return cwd_str; -} - VALUE rb_get_expanded_load_path(void) { @@ -115,7 +106,7 @@ rb_get_expanded_load_path(void) https://github.com/ruby/ruby/blob/trunk/ruby_2_4/load.c#L106 int has_relative = 0, has_non_cache = 0; rb_construct_expanded_load_path(EXPAND_ALL, &has_relative, &has_non_cache); if (has_relative) { - vm->load_path_check_cache = load_path_getcwd(); + vm->load_path_check_cache = rb_dir_getwd_ospath(); } else if (has_non_cache) { /* Non string object. */ @@ -133,7 +124,7 @@ rb_get_expanded_load_path(void) https://github.com/ruby/ruby/blob/trunk/ruby_2_4/load.c#L124 } else if (vm->load_path_check_cache) { int has_relative = 1, has_non_cache = 1; - VALUE cwd = load_path_getcwd(); + VALUE cwd = rb_dir_getwd_ospath(); if (!rb_str_equal(vm->load_path_check_cache, cwd)) { /* Current working directory or filesystem encoding was changed. Expand relative load path and non-cacheable objects again. */ Index: ruby_2_4/dir.c =================================================================== --- ruby_2_4/dir.c (revision 62783) +++ ruby_2_4/dir.c (revision 62784) @@ -74,6 +74,7 @@ char *strchr(char*,char); https://github.com/ruby/ruby/blob/trunk/ruby_2_4/dir.c#L74 #define rmdir(p) rb_w32_urmdir(p) #undef opendir #define opendir(p) rb_w32_uopendir(p) +#define ruby_getcwd() rb_w32_ugetcwd(NULL, 0) #define IS_WIN32 1 #else #define IS_WIN32 0 @@ -1048,26 +1049,52 @@ dir_s_chdir(int argc, VALUE *argv, VALUE https://github.com/ruby/ruby/blob/trunk/ruby_2_4/dir.c#L1049 } VALUE -rb_dir_getwd(void) +rb_dir_getwd_ospath(void) { char *path; VALUE cwd; - int fsenc = rb_enc_to_index(rb_filesystem_encoding()); + VALUE path_guard; - if (fsenc == ENCINDEX_US_ASCII) fsenc = ENCINDEX_ASCII; +#undef RUBY_UNTYPED_DATA_WARNING +#define RUBY_UNTYPED_DATA_WARNING 0 + path_guard = Data_Wrap_Struct((VALUE)0, NULL, RUBY_DEFAULT_FREE, NULL); path = my_getcwd(); -#ifdef __APPLE__ + DATA_PTR(path_guard) = path; +#ifdef _WIN32 + cwd = rb_utf8_str_new_cstr(path); + OBJ_TAINT(cwd); +#elif defined __APPLE__ cwd = rb_str_normalize_ospath(path, strlen(path)); OBJ_TAINT(cwd); #else cwd = rb_tainted_str_new2(path); #endif - rb_enc_associate_index(cwd, fsenc); + DATA_PTR(path_guard) = 0; xfree(path); return cwd; } +VALUE +rb_dir_getwd(void) +{ + rb_encoding *fs = rb_filesystem_encoding(); + int fsenc = rb_enc_to_index(fs); + VALUE cwd = rb_dir_getwd_ospath(); + + switch (fsenc) { + case ENCINDEX_US_ASCII: + fsenc = ENCINDEX_ASCII; + case ENCINDEX_ASCII: + break; +#if defined _WIN32 || defined __APPLE__ + default: + return rb_str_conv_enc(cwd, NULL, fs); +#endif + } + return rb_enc_associate_index(cwd, fsenc); +} + /* * call-seq: * Dir.getwd -> string Index: ruby_2_4/win32/win32.c =================================================================== --- ruby_2_4/win32/win32.c (revision 62783) +++ ruby_2_4/win32/win32.c (revision 62784) @@ -4654,43 +4654,61 @@ clock_getres(clockid_t clock_id, struct https://github.com/ruby/ruby/blob/trunk/ruby_2_4/win32/win32.c#L4654 } /* License: Ruby's */ -char * -rb_w32_getcwd(char *buffer, int size) +static char * +w32_getcwd(char *buffer, int size, UINT cp) { - char *p = buffer; - int len; + WCHAR *p; + int wlen, len; - len = GetCurrentDirectory(0, NULL); + len = GetCurrentDirectoryW(0, NULL); if (!len) { errno = map_errno(GetLastError()); return NULL; } - if (p) { + if (buffer && size < len) { + errno = ERANGE; + return NULL; + } + + p = ALLOCA_N(WCHAR, len); + if (!GetCurrentDirectoryW(len, p)) { + errno = map_errno(GetLastError()); + return NULL; + } + + wlen = translate_wchar(p, L'\\', L'/') - p + 1; + len = WideCharToMultiByte(cp, 0, p, wlen, NULL, 0, NULL, NULL); + if (buffer) { if (size < len) { errno = ERANGE; return NULL; } } else { - p = malloc(len); - size = len; - if (!p) { + buffer = malloc(len); + if (!buffer) { errno = ENOMEM; return NULL; } } + WideCharToMultiByte(cp, 0, p, wlen, buffer, len, NULL, NULL); - if (!GetCurrentDirectory(size, p)) { - errno = map_errno(GetLastError()); - if (!buffer) - free(p); - return NULL; - } + return buffer; +} - translate_char(p, '\\', '/', filecp()); +/* License: Ruby's */ +char * +rb_w32_getcwd(char *buffer, int size) +{ + return w32_getcwd(buffer, size, filecp()); +} - return p; +/* License: Ruby's */ +char * +rb_w32_ugetcwd(char *buffer, int size) +{ + return w32_getcwd(buffer, size, CP_UTF8); } /* License: Artistic or GPL */ Index: ruby_2_4/win32/dir.h =================================================================== --- ruby_2_4/win32/dir.h (revision 62783) +++ ruby_2_4/win32/dir.h (revision 62784) @@ -33,6 +33,7 @@ long rb_w32_telldir(DIR *); https://github.com/ruby/ruby/blob/trunk/ruby_2_4/win32/dir.h#L33 void rb_w32_seekdir(DIR *, long); void rb_w32_rewinddir(DIR *); void rb_w32_closedir(DIR *); +char *rb_w32_ugetcwd(char *, int); #define opendir(s) rb_w32_opendir((s)) #define readdir(d) rb_w32_readdir((d), 0) Index: ruby_2_4/util.c =================================================================== --- ruby_2_4/util.c (revision 62783) +++ ruby_2_4/util.c (revision 62784) @@ -511,7 +511,10 @@ ruby_getcwd(void) https://github.com/ruby/ruby/blob/trunk/ruby_2_4/util.c#L511 char *buf = xmalloc(2); strcpy(buf, "."); #elif defined HAVE_GETCWD +# undef RUBY_UNTYPED_DATA_WARNING +# define RUBY_UNTYPED_DATA_WARNING 0 # if defined NO_GETCWD_MALLOC + VALUE guard = Data_Wrap_Struct((VALUE)0, NULL, RUBY_DEFAULT_FREE, NULL); int size = 200; char *buf = xmalloc(size); @@ -519,17 +522,22 @@ ruby_getcwd(void) https://github.com/ruby/ruby/blob/trunk/ruby_2_4/util.c#L522 int e = errno; if (e != ERANGE) { xfree(buf); + DATA_PTR(guard) = NULL; rb_syserr_fail(e, "getcwd"); } size *= 2; + DATA_PTR(guard) = buf; buf = xrealloc(buf, size); } # else + VALUE guard = Data_Wrap_Struct((VALUE)0, NULL, free, NULL); char *buf, *cwd = getcwd(NULL, 0); + DATA_PTR(guard) = cwd; if (!cwd) rb_sys_fail("getcwd"); buf = ruby_strdup(cwd); /* allocate by xmalloc */ free(cwd); # endif + DATA_PTR(RB_GC_GUARD(guard)) = NULL; #else # ifndef PATH_MAX # define PATH_MAX 8192 Index: ruby_2_4/internal.h =================================================================== --- ruby_2_4/internal.h (revision 62783) +++ ruby_2_4/internal.h (revision 62784) @@ -982,6 +982,9 @@ void ruby_register_rollback_func_for_ens https://github.com/ruby/ruby/blob/trunk/ruby_2_4/internal.h#L982 /* debug.c */ PRINTF_ARGS(void ruby_debug_printf(const char*, ...), 1, 2); +/* dir.c */ +VALUE rb_dir_getwd_ospath(void); + /* dmyext.c */ void Init_enc(void); void Init_ext(void); Index: ruby_2_4/version.h =================================================================== --- ruby_2_4/version.h (revision 62783) +++ ruby_2_4/version.h (revision 62784) @@ -1,6 +1,6 @@ https://github.com/ruby/ruby/blob/trunk/ruby_2_4/version.h#L1 #define RUBY_VERSION "2.4.4" #define RUBY_RELEASE_DATE "2018-03-17" -#define RUBY_PATCHLEVEL 259 +#define RUBY_PATCHLEVEL 260 #define RUBY_RELEASE_YEAR 2018 #define RUBY_RELEASE_MONTH 3 Index: ruby_2_4 =================================================================== --- ruby_2_4 (revision 62783) +++ ruby_2_4 (revision 62784) Property changes on: ruby_2_4 ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /trunk:r58745,58780,59040,60743 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/