From a7256d7a006b75adf690defd1b41271a77a15117 Mon Sep 17 00:00:00 2001 From: nagachika Date: Thu, 11 Apr 2013 16:47:45 +0000 Subject: merge revision(s) 39697,39701,39716,39740,39751: [Backport #8069] * win32/file.c (rb_file_expand_path_internal): Expand home directory when used as second parameter (dir_string). [ruby-core:53168] [Bug #8034] * test/ruby/test_file_exhaustive.rb: add test to verify. * win32/file.c (get_user_from_path): add internal function that retrieves username from supplied path (refactored). * win32/file.c (rb_file_expand_path_internal): refactor expansion of user home to use get_user_from_path and cover dir_string corner cases. [ruby-core:53168] [Bug #8034] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_2_0_0@40249 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- win32/file.c | 107 +++++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 78 insertions(+), 29 deletions(-) (limited to 'win32') diff --git a/win32/file.c b/win32/file.c index dfe122480f..350f8da182 100644 --- a/win32/file.c +++ b/win32/file.c @@ -317,13 +317,45 @@ replace_to_long_name(wchar_t **wfullpath, size_t size, int heap) 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, *wdir = 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; @@ -404,32 +436,10 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na } } 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++; + result = get_user_from_path(&wpath_pos, 1, cp, path_cp, path_encoding); - *pos = '\0'; - convert_wchar_to_mb(wuser, &user, &size, cp); - - /* convert to VALUE and set the path encoding */ - if (path_cp == INVALID_CODE_PAGE) { - VALUE 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); - } - - xfree(wpath); - if (user) - xfree(user); + if (wpath) + xfree(wpath); rb_raise(rb_eArgError, "can't find user %s", StringValuePtr(result)); } @@ -442,9 +452,38 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na } /* convert char * to wchar_t */ - convert_mb_to_wchar(dir, &wdir, NULL, &wdir_len, cp); + 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; - if (wdir_len >= 2 && wdir[1] == L':') { + 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; @@ -466,6 +505,16 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na 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 */ @@ -515,7 +564,7 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na if (!tainted && OBJ_TAINTED(dir)) tainted = 1; - wcsncpy(buffer_pos, wdir, wdir_len); + wcsncpy(buffer_pos, wdir_pos, wdir_len); buffer_pos += wdir_len; } -- cgit v1.2.3