From 5b06e833453dcbbf4da69a5f98d50e565d4300ef Mon Sep 17 00:00:00 2001 From: nobu Date: Sun, 8 Mar 2015 07:57:38 +0000 Subject: dir.c: glob short names * dir.c (glob_helper): match patterns against legacy short names too, not only ordinary names. [ruby-core:67954] [Bug #10819] * win32/dir.h (struct direct): add short name members. * win32/win32.c (opendir_internal, readdir_internal): ditto. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@49892 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 9 +++++++++ dir.c | 14 +++++++++++++- test/ruby/test_dir.rb | 6 +++++- win32/dir.h | 2 ++ win32/win32.c | 32 ++++++++++++++++++++++++++------ 5 files changed, 55 insertions(+), 8 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2669167b7f..5e7790783a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +Sun Mar 8 16:57:35 2015 Nobuyoshi Nakada + + * dir.c (glob_helper): match patterns against legacy short names + too, not only ordinary names. [ruby-core:67954] [Bug #10819] + + * win32/dir.h (struct direct): add short name members. + + * win32/win32.c (opendir_internal, readdir_internal): ditto. + Sat Mar 7 09:36:05 2015 SHIBATA Hiroshi * array.c: document that first element is kept when using diff --git a/dir.c b/dir.c index 89f7bb89cb..8e7f1c945b 100644 --- a/dir.c +++ b/dir.c @@ -1554,6 +1554,18 @@ glob_func_caller(VALUE val) return Qnil; } +static inline int +dirent_match(const char *pat, rb_encoding *enc, const char *name, const struct dirent *dp, int flags) +{ + if (fnmatch(pat, enc, name, flags) == 0) return 1; +#ifdef _WIN32 + if (dp->d_altname) { + if (fnmatch(pat, enc, dp->d_altname, flags) == 0) return 1; + } +#endif + return 0; +} + static int glob_helper( const char *path, @@ -1753,7 +1765,7 @@ glob_helper( # endif case PLAIN: case MAGICAL: - if (fnmatch(p->str, enc, name, flags) == 0) + if (dirent_match(p->str, enc, name, dp, flags)) *new_end++ = p->next; default: break; diff --git a/test/ruby/test_dir.rb b/test/ruby/test_dir.rb index 85fdd16dfd..69ea57d0a7 100644 --- a/test/ruby/test_dir.rb +++ b/test/ruby/test_dir.rb @@ -256,7 +256,11 @@ class TestDir < Test::Unit::TestCase skip unless File.directory?(short) entries = Dir.glob("#{short}/Common*") assert_not_empty(entries, bug10819) - assert_equal(Dir.glob("#{File.expand_path(short)}/Common*"), entries, bug10819) + long = File.expand_path(short) + assert_equal(Dir.glob("#{long}/Common*"), entries, bug10819) + wild = short.sub(/1\z/, '*') + assert_include(Dir.glob(wild), long, bug10819) + assert_empty(entries - Dir.glob("#{wild}/Common*"), bug10819) end end diff --git a/win32/dir.h b/win32/dir.h index 0e1bff0846..5a97f54623 100644 --- a/win32/dir.h +++ b/win32/dir.h @@ -13,6 +13,8 @@ struct direct long d_namlen; ino_t d_ino; char *d_name; + char *d_altname; /* short name */ + short d_altlen; char d_isdir; /* directory */ char d_isrep; /* reparse point */ }; diff --git a/win32/win32.c b/win32/win32.c index 48712f7b9c..73163f6171 100644 --- a/win32/win32.c +++ b/win32/win32.c @@ -1870,6 +1870,7 @@ opendir_internal(WCHAR *wpath, const char *filename) HANDLE fh; DIR *p; long len; + long altlen; long idx; WCHAR *tmpW; char *tmp; @@ -1908,12 +1909,13 @@ opendir_internal(WCHAR *wpath, const char *filename) // do { len = lstrlenW(fd.cFileName) + 1; + altlen = lstrlenW(fd.cAlternateFileName) + 1; // // bump the string table size by enough for the // new name and it's null terminator // - tmpW = realloc(p->start, (idx + len) * sizeof(WCHAR)); + tmpW = realloc(p->start, (idx + len + altlen) * sizeof(WCHAR)); if (!tmpW) { error: rb_w32_closedir(p); @@ -1924,6 +1926,7 @@ opendir_internal(WCHAR *wpath, const char *filename) p->start = tmpW; memcpy(&p->start[idx], fd.cFileName, len * sizeof(WCHAR)); + memcpy(&p->start[idx + len], fd.cAlternateFileName, altlen * sizeof(WCHAR)); if (p->nfiles % DIRENT_PER_CHAR == 0) { tmp = realloc(p->bits, p->nfiles / DIRENT_PER_CHAR + 1); @@ -1938,7 +1941,7 @@ opendir_internal(WCHAR *wpath, const char *filename) SetBit(p->bits, BitOfIsRep(p->nfiles)); p->nfiles++; - idx += len; + idx += len + altlen; } while (FindNextFileW(fh, &fd)); FindClose(fh); p->size = idx; @@ -2023,6 +2026,7 @@ move_to_next_entry(DIR *dirp) if (dirp->curr) { dirp->loc++; dirp->curr += lstrlenW(dirp->curr) + 1; + dirp->curr += lstrlenW(dirp->curr) + 1; if (dirp->curr >= (dirp->start + dirp->size)) { dirp->curr = NULL; } @@ -2035,11 +2039,16 @@ move_to_next_entry(DIR *dirp) // /* License: Ruby's */ static BOOL -win32_direct_conv(const WCHAR *file, struct direct *entry, const void *enc) +win32_direct_conv(const WCHAR *file, const WCHAR *alt, struct direct *entry, const void *enc) { UINT cp = *((UINT *)enc); if (!(entry->d_name = wstr_to_mbstr(cp, file, -1, &entry->d_namlen))) return FALSE; + if (alt && *alt) { + long altlen = 0; + entry->d_altname = wstr_to_mbstr(cp, alt, -1, &altlen); + entry->d_altlen = altlen; + } return TRUE; } @@ -2091,16 +2100,21 @@ rb_w32_conv_from_wstr(const WCHAR *wstr, long *lenp, rb_encoding *enc) /* License: Ruby's */ static BOOL -ruby_direct_conv(const WCHAR *file, struct direct *entry, const void *enc) +ruby_direct_conv(const WCHAR *file, const WCHAR *alt, struct direct *entry, const void *enc) { if (!(entry->d_name = rb_w32_conv_from_wstr(file, &entry->d_namlen, enc))) return FALSE; + if (alt && *alt) { + long altlen = 0; + entry->d_altname = rb_w32_conv_from_wstr(alt, &altlen, enc); + entry->d_altlen = altlen; + } return TRUE; } /* License: Artistic or GPL */ static struct direct * -readdir_internal(DIR *dirp, BOOL (*conv)(const WCHAR *, struct direct *, const void *), const void *enc) +readdir_internal(DIR *dirp, BOOL (*conv)(const WCHAR *, const WCHAR *, struct direct *, const void *), const void *enc) { static int dummy = 0; @@ -2111,7 +2125,11 @@ readdir_internal(DIR *dirp, BOOL (*conv)(const WCHAR *, struct direct *, const v // if (dirp->dirstr.d_name) free(dirp->dirstr.d_name); - conv(dirp->curr, &dirp->dirstr, enc); + if (dirp->dirstr.d_altname) + free(dirp->dirstr.d_altname); + dirp->dirstr.d_altname = 0; + dirp->dirstr.d_altlen = 0; + conv(dirp->curr, dirp->curr + lstrlenW(dirp->curr) + 1, &dirp->dirstr, enc); // // Fake inode @@ -2202,6 +2220,8 @@ rb_w32_closedir(DIR *dirp) if (dirp) { if (dirp->dirstr.d_name) free(dirp->dirstr.d_name); + if (dirp->dirstr.d_altname) + free(dirp->dirstr.d_altname); if (dirp->start) free(dirp->start); if (dirp->bits) -- cgit v1.2.3