Bug #9648

Dir.glob('../*') shows unexpected result in a symbolic linked directory on Windows

Added by Hiroshi Shirosaki over 1 year ago. Updated over 1 year ago.

[ruby-core:61552]
Status:Closed
Priority:Normal
Assignee:Nobuyoshi Nakada
ruby -v:ruby 2.2.0dev (2014-03-17 trunk 45356) [x64-mingw32] Backport:2.0.0: DONTNEED, 2.1: DONTNEED

Description

Dir.glob('../*') shows unexpected result if current directory is a symbolic linked directory on Windows.
This issue seems to be introduced by r44802.

The following is a test case.

C:\foo>mklink /D bar V:\
symbolic link created for bar <<===>> V:\

C:\foo>cd bar

C:\foo\bar>ruby -ve "p Dir.glob('../*')"
ruby 1.9.3p392 (2013-02-22) [i386-mingw32]
["../a", "../bar"]

C:\foo\bar>\rubyinstaller\sandbox\ruby21_build\miniruby.exe -ve "p Dir.glob('../*')"
ruby 2.2.0dev (2014-02-04 trunk 45356) [x64-mingw32]
[]


C:\foo\bar>dir ..
 Volume in drive C is OS
 Volume Serial Number is 6629-B36B

 Directory of C:\foo

2014/03/17  18:58    <DIR>          .
2014/03/17  18:58    <DIR>          ..
2014/03/17  18:45                 6 a
2014/03/17  18:58    <SYMLINKD>     bar [V:\]
               1 File(s)              6 bytes
               3 Dir(s)  81,915,052,032 bytes free

Associated revisions

Revision 45965
Added by Nobuyoshi Nakada over 1 year ago

dir.c: match plain names as-is

  • dir.c (glob_pattern_type): separate names with alphabet but no magical from plain.
  • dir.c (glob_helper): match plain names as-is to treat super-root same as the root. [Bug #9648]

Revision 45965
Added by Nobuyoshi Nakada over 1 year ago

dir.c: match plain names as-is

  • dir.c (glob_pattern_type): separate names with alphabet but no magical from plain.
  • dir.c (glob_helper): match plain names as-is to treat super-root same as the root. [Bug #9648]

Revision 45967
Added by Nobuyoshi Nakada over 1 year ago

dir.c: fix conditions for ALPHA

  • dir.c (has_magic): return ALPHA at alphabetical name regardless FNM_CASEFOLD flag.
  • dir.c (glob_helper): fix conditions for ALPHA. [Bug #9648]

Revision 45967
Added by Nobuyoshi Nakada over 1 year ago

dir.c: fix conditions for ALPHA

  • dir.c (has_magic): return ALPHA at alphabetical name regardless FNM_CASEFOLD flag.
  • dir.c (glob_helper): fix conditions for ALPHA. [Bug #9648]

Revision 45968
Added by Nobuyoshi Nakada over 1 year ago

dir.c: set PLAIN for non-magical

  • dir.c (glob_make_pattern): set PLAIN for non-magical path to skip parts which not need to glob. [Bug #9648]

Revision 45968
Added by Nobuyoshi Nakada over 1 year ago

dir.c: set PLAIN for non-magical

  • dir.c (glob_make_pattern): set PLAIN for non-magical path to skip parts which not need to glob. [Bug #9648]

Revision 45969
Added by Nobuyoshi Nakada over 1 year ago

dir.c: try match PLAIN

  • dir.c (glob_helper): try match PLAIN as well as ALPHA, which are separated by previous commits. [Bug #9648]

Revision 45969
Added by Nobuyoshi Nakada over 1 year ago

dir.c: try match PLAIN

  • dir.c (glob_helper): try match PLAIN as well as ALPHA, which are separated by previous commits. [Bug #9648]

History

#1 Updated by Nobuyoshi Nakada over 1 year ago

  • Status changed from Open to Feedback

Is there any files at V:/?

#2 Updated by Usaku NAKAMURA over 1 year ago

  • Backport changed from 2.0.0: UNKNOWN, 2.1: UNKNOWN to 2.0.0: DONTNEED, 2.1: DONTNEED

I've tested on 1.9.3-p545, 2.0.0-p451, 2.1.1 and found they are ok.
This problem is only with trunk.

#3 Updated by Nobuyoshi Nakada over 1 year ago

Usaku NAKAMURA wrote:

I've tested on 1.9.3-p545, 2.0.0-p451, 2.1.1 and found they are ok.

‘OK’ means it globs as if it is a real directory but not a symlink?

This problem is only with trunk.

It doesn’t glob anything, neither the parent of the symlink, or the target?

#4 Updated by Usaku NAKAMURA over 1 year ago

Hi,

In message " [ruby-trunk - Bug #9648] Dir.glob('../*') shows unexpected result in a symbolic linked directory on Windows"
on Apr.26,2014 16:22:34, nobu@ruby-lang.org wrote:

'ok' means it globs as if it is a real directory but not a symlink?

It's too difficult for me to say it in English.

C:\foo に V:\ へのsymlinkである bar (つまり C:\foo\bar) を作り、
そこに chdir した後で Dir.glob('../*') するわけですが、結果は
期待通り C:\foo の中身(V:\ でなく)を返します。

This problem is only with trunk.

It doesn't glob anything, neither the parent of the symlink, or the target?

何も返しません。なお、targetである V:\ にはparentが存在しないことは
留意すべき事項かもしれません。
ちなみに、targetを適当なディレクトリ V:\baz に変更して実行すると、
なぜかtrunkでも正しい結果(C:\fooの中身)を返します。

Regards,
--
U.Nakamura usa@garbagecollect.jp

#5 Updated by Hiroshi Shirosaki over 1 year ago

Nobuyoshi Nakada wrote:

Is there any files at V:/?

Yes, there are some files and directories at V:/.
If no files and directories exist at V:/, the result is same.

#6 Updated by Hiroshi Shirosaki over 1 year ago

  • Assignee set to Nobuyoshi Nakada
  • Status changed from Feedback to Assigned

If current directory is C:\foo\bar (linked to V:), READDIR of '.' (i.e. FindFirstFile(".\\*", &d)) globs linked directory (V:/), but the result doesn't have '..'.
So we cannot trace parent directory.

Skipping READDIR usage for this case solves the bug.

diff --git a/dir.c b/dir.c
index f456e8b..91a8495 100644
--- a/dir.c
+++ b/dir.c
@@ -1397,6 +1397,14 @@ glob_helper(

     if (exist == NO || isdir == NO) return 0;

+    if (!(magical || recursive) && (FNM_SYSCASE && plain)) {
+   /* READDIR will not return '..' at a directory which is symbolic linked to
+      a root directory on Windows. We don't use READDIR to get '..'. */
+   struct glob_pattern *p = *beg;
+   if (p && strcmp(p->str, "..") == 0)
+       goto literally;
+    }
+
     if (magical || recursive || ((FNM_SYSCASE || HAVE_HFS) && plain)) {
    struct dirent *dp;
    DIR *dirp;

#7 Updated by Nobuyoshi Nakada over 1 year ago

Hiroshi Shirosaki wrote:

If current directory is C:\foo\bar (linked to V:), READDIR of '.' (i.e. FindFirstFile(".\\*", &d)) globs linked directory (V:/), but the result doesn't have '..'.
So we cannot trace parent directory.

In that case, what should it return?

  1. ignores it and globs as if it were not a symlink
  2. matches nothing, since there is no parent directory of a root directory
  3. treat the parent directory same as the root directory, like unixen systems

Skipping READDIR usage for this case solves the bug.

I'm not sure what is a "bug" yet.

+    if (!(magical || recursive) && (FNM_SYSCASE && plain)) {

This "super-root" issue is not common to all case-insensitive systems,
but seems a DOSISH centric probably.

#8 Updated by Usaku NAKAMURA over 1 year ago

Nobuyoshi Nakada wrote:

In that case, what should it return?

  1. ignores it and globs as if it were not a symlink
  2. matches nothing, since there is no parent directory of a root directory
  3. treat the parent directory same as the root directory, like unixen systems

First I think it should returns the directory that the symlink exists (maybe 1 ?),
but now I think it should be 3.

Skipping READDIR usage for this case solves the bug.

I'm not sure what is a "bug" yet.

I've not tested the patch yet, but I think there are some *bug*s now.

  1. glob should return the root itself for the parent of the root, like unixen.
  2. glob should return the parent of the symlinked directory instead of the parent of the symlink, like unixen, too.

#9 Updated by Hiroshi Shirosaki over 1 year ago

Usaku NAKAMURA wrote:

Nobuyoshi Nakada wrote:

In that case, what should it return?

  1. ignores it and globs as if it were not a symlink
  2. matches nothing, since there is no parent directory of a root directory
  3. treat the parent directory same as the root directory, like unixen systems

First I think it should returns the directory that the symlink exists (maybe 1 ?),
but now I think it should be 3.

I thought 1. is spec on Windows because old version ruby, dir command and FindFirstFile behavior is same.
I agree to change behavior unixen systems.

#10 Updated by Nobuyoshi Nakada over 1 year ago

Unfortunately, it seems to need tools more than expected to deal with symbolic links on Windows.
So I'll fix only the empty result for the meantime.

#11 Updated by Nobuyoshi Nakada over 1 year ago

  • Status changed from Assigned to Closed
  • % Done changed from 0 to 100

Applied in changeset r45965.


dir.c: match plain names as-is

  • dir.c (glob_pattern_type): separate names with alphabet but no magical from plain.
  • dir.c (glob_helper): match plain names as-is to treat super-root same as the root. [Bug #9648]

Also available in: Atom PDF